How can result of .check((css("input", "name").count() be used in a for loop

I have a list of requests. The first request is a get request the second is a post request.
In the get request I count all the input tags.
The number of input tags I want to use in a for loop for the post request.
The code looks as follows:

private HttpRequestActionBuilder getAction(HtmlRequest htmlRequest) {

		HttpRequestActionBuilder b = null;

		String url = htmlRequest.getUrl().replace(rootUrl, "");

		switch (htmlRequest.getMethod().toLowerCase()) {
		case "post":
			b = http("requestPost" + url).post(url);

			// how can I get the count from the get request
			for (int i = 0; i < count; i++) {
				// do something
			}

			break;

		case "get":
			b = http("requestGet" + url).get(url);

			b = b.check((css("input", "name").count().saveAs("count")));

			break;
		}

		return b;
	}

The scenario looks like

         ...
         ArrayList<ChainBuilder> chains = new ArrayList<>();
			
			for (HtmlRequest r : htmlRequests) {

				HttpRequestActionBuilder b = getAction(r);

				final ChainBuilder chain = exec(b)//
						.exec(...)
						.exec(...);
				chains.add(chain);
				
			}

			scn = scenario("RecordedSimulation").exec(initScenario()).exec(chains);

Many thanks for your help.

Hi @Maurus,

As you saved your count into session (with saveAs), you will need to retrieve it from session as well.

Have a look to our Session API documentation:

Cheers!

Hi @sbrevet,
I did look at the session API and I did not find a solution.
All I want is to use count retrieved from the get request.
When I do

            int count = 0;

            ArrayList<ChainBuilder> chains = new ArrayList<>();
			
			for (HtmlRequest r : htmlRequests) {

				HttpRequestActionBuilder b = getAction(r);

				final ChainBuilder chain = exec(b)//
						.exec(session -> {count = session.get("count"); return session;}))
						.exec(...);
				chains.add(chain);	
			}

count is not set in getAction(r).

Please provide a minimal but yet full reproducer.

It’s hard to understand what you did with such extract.
See SSCCE.org.

Cheers!

I made an example to show the point. In the example “user3” is a valid user name.
In the saved file you can see if the user is logged in or not.
Case 1 is working
Case 2 is not working so “count” is not set to 3.
Case 3 is not working “#{user}” is not set.
What needs to be done to make case 2 and 3 work.

import static io.gatling.javaapi.core.CoreDsl.atOnceUsers;
import static io.gatling.javaapi.core.CoreDsl.bodyString;
import static io.gatling.javaapi.core.CoreDsl.css;
import static io.gatling.javaapi.core.CoreDsl.exec;
import static io.gatling.javaapi.core.CoreDsl.regex;
import static io.gatling.javaapi.core.CoreDsl.scenario;
import static io.gatling.javaapi.http.HttpDsl.http;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;

import io.gatling.javaapi.core.ChainBuilder;
import io.gatling.javaapi.core.ScenarioBuilder;
import io.gatling.javaapi.core.Simulation;
import io.gatling.javaapi.http.HttpProtocolBuilder;

public class DemostoreSimulation extends Simulation {

	private static final String DOMAIN = "demostore.gatling.io";
	private static final HttpProtocolBuilder HTTP_PROTOCOL = http.baseUrl("https://" + DOMAIN);

	private static int count;

	private static final ScenarioBuilder scn = //
			scenario("DemostoreSimulation") //
					.exec(http("Load Home Page") //
							.get("/login") //
							.check(regex("<title>Gatling Demo-Store</title>").exists()) //
							.check(css("#_csrf", "content").saveAs("csrfValue")) //
							.check((css("input", "name").count().saveAs("count")))) //
					.exec(session -> {
						count = session.get("count");
						System.out.println("count " + count);
						session.set("user", "user");
						return session;
					})//
					.exec( //
							http("Login User") //
									.post("/login") //
									.formParam("_csrf", "#{csrfValue}") //
									// case 1
									// this works
									.formParam("username", "user" + "#{count}") //

									// case 2
									// this does not work
									// .formParam("username", "#{user}" + "#{count}") //

									// case 3
									// this does not work
									// .formParam("username", "user" + count) //

									.formParam("password", "pass") //
									.check(bodyString().saveAs("loggedId"))) //
					.exec(writeToFile("loggedId")) //
					.pause(2) //
					.exec(http("Checkout").get("/cart/checkout")); //

	private static ChainBuilder writeToFile(String name) {
		return

		exec(session -> {

			PrintWriter writer = null;
			try {
				writer = new PrintWriter(new FileOutputStream(new File("c:\\temp\\gatling\\" + name + ".html"), false));
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			writer.write(session.getString(name));
			writer.write("\n");
			writer.close();
			return session;
		});
	}

	//
	{ //
		setUp(scn.injectOpen(atOnceUsers(1))).protocols(HTTP_PROTOCOL); //
	} //
}

session is immutable, so, you’ll have to return the result of the operation (not the initial instance).

					.exec(session -> {
						count = session.get("count");
						System.out.println("count " + count);
-						session.set("user", "user");
-						return session;
+						return session.set("user", "user");
					})

See the Warning block in the documentation

1 Like

Thanks for the answer which solves case 2.
How can I make case 3 work?

This is very wrong. You shouldn’t store user specific data in a global reference, you’re bound to experience initialization and race condition issues. Case 3 can NOT possibly work.

Sorry, I don’t understand “case 3”.
Your count variable doesn’t mean anything in that context.
Remember that gatling works in high load… so, your external variable is likely to be changed by another user.

at worst, you may want to use a custom function here:

- .formParam("username", "user" + count)
+ .formParam("username", session -> "user" + session.get("count"))

Cheers!

Thanks for the answer which also solves case 3.
The cases 1 - 3 where not meant to make a lot of sense. They were meant as illustration of the original question.
Nevertheless the original question is still not answered.
I need count as a number so that it can be used in the for loop.

You can’t use Java for loop, you must use Gatling loops.

I am very new to Gatling.
Can you please show me how it is done in code?

If you new in Gatling I suggest to do Gatling Accademy - it’s free and show basics.
If you looking for some examples of using loop in Gatling you can chcek my repo and this Case:

I did all you suggested and even more.
Still I am not able to find the solution. So please show me in code the answer of the first question.
Instead of
b = b.check((css(“input”, “name”).count().saveAs(“count”)));
b = b.check(css(“input”, “name”).findAll().saveAs(“paramNames”)));

All I would like to do is getting all the names of the input fields form the first request and use them in the second request.
So if I can use count in the second request I can store the field name numbered and then use the numbered names to get the real names in the second request.
The target is to find all the hidden fields at run time and setting them instead of hard coding them for every request as it is done in the academy example.

The target is to find all the hidden fields at run time and setting them instead of hard coding them for every request as it is done in the academy example.

If you had properly explained what you were trying to do in the first place, people would have directly pointed to the form check and its post counterpart.

Then, remember that Gatling doesn’t execute real web browser. In particular, it doesn’t execute Javascript and can only parse HTTP responses. So if your HTML is not rendered server-side but it actually generated by a Javascript based client app, CSS selectors can’t possibly work. In this case, you have to reason on the API calls, not the browser DOM.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.