RestAssured with duplicate query parameters - java

Working on an automated test pack that uses REST-assured rest-assured-3.3.0. Have an endpoint to test that has a number of duplicate Query parameters used to drive it's search function:
/count?taskTypes=EAS&taskTypes=MBO&taskTypes=OTHER&taskAges=NEW&taskAges=EXISTING&ageSelection=ALL
REST-assured provides a params(Map<String, ?> var1) in it's request specification to pass in parameters. However this uses Map which can not contain duplicate keys. Therefore in order to construct the query in test code I am setting up the parameters and associated values in a Multimap:
import com.google.common.collect.Multimap;
Multimap<String, String> searchParams = ArrayListMultimap.create();
searchParams.put("taskTypes", "EAS");
searchParams.put("taskTypes", "MBO");
searchParams.put("taskTypes", "OTHER");
searchParams.put("taskAges", "NEW");
searchParams.put("taskAges", "EXISTING");
searchParams.put("ageSelection", "ALL");
The Multimap is then passed into a function to format the query and set up a GET request using REST-assured:
import org.apache.http.client.utils.URIBuilder;
import io.restassured.http.Method;
import io.restassured.response.ExtractableResponse;
import io.restassured.specification.RequestSpecification;
protected ExtractableResponse request(Method method, Multimap<String, ?> params, String url)
{
URIBuilder builder = new URIBuilder();
for (Map.Entry<String, ?> entry : params.entries()) {
builder.addParameter(entry.getKey(), entry.getValue().toString());
}
try {
url = url + builder.build().toString();
} catch(URISyntaxException e) {}
return getRequestSpec()
.when()
.headers("Content-Type", "application/json")
.request(method, url)
.then()
.spec(getResponseSpec(method))
.extract();
}
Running this code results in a request with the following parameters:
/count?taskTypes=OTHER&taskAges=EXISTING&ageSelection=ALL
The problem is that REST-assured appears to remove the duplicate query parameters passed to it in the url parameter. Interestingly REST-assured offers the following interface given().queryParam("param", 1,2,3)

Check that for loop here:
URIBuilder builder = new URIBuilder();
for (Map.Entry<String, ?> entry : params.entries()) {
builder.addParameter(entry.getKey(), entry.getValue().toString());
}
looks like despite using Multimap for params you are still ending with Map for the builder. Here is where you got rid of duplicated keys anyway.

queryParam(String var1, Collection<?> var2)
should work. I have used it in the past for rest-assured-3.*.
Example:
List<String> multiQuery = new ArrayList<>();
multiquery.add("EAS");
multiquery.add("MBO");
queryParam("taskTypes", multiQuery);

Related

Elasticsearch UpdateByQueryRequest using XContentBuilder

I have UpdateRequest for which I can set XContentBuilder with : updateRequest.doc(XContentBuilder);. Is it possible to perform the same action for UpdateByQueryRequest? If not can I transform XContentBuilder to Script? What are alternatives to Script?
If you look at the source code of Elasticsearch's UpdateByQueryRequest, you notice, what you wanted is possible using the below method, as you can notice, it can covert the script to XContentBuilder.
#Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
if (getScript() != null) {
builder.field("script");
getScript().toXContent(builder, params);
}
getSearchRequest().source().innerToXContent(builder, params);
builder.endObject();
return builder;
}
ES docs didn't have the sample example of converting script to XContentBuilder, but as method is present, you can simply make it work :)
What I ended up doing is converting to Map, and passing it as a script:
Map<String, Object> params = mapper.readValue(Strings.toString(XContentBuilder), Map.class);
UpdateByQueryRequest updateRequest = new UpdateByQueryRequest("document");
updateRequest.setScript(new Script(ScriptType.INLINE,
"painless",
"ctx._source.document = params.document",
params));
I will leave the question open in case someone finds a better solution.

How to Execute single GET request multiple time with different set of Headers & then need to validate response as well using java API automation

This is my code where I am using headers. I wasn't to execute same login API GET request with multiple set of headers and then need to validate response as well .
// API Test for Login
#Test(priority = 1)
public void GetLoginAPI() throws ClientProtocolException, IOException, JSONException {
HashMap<String, String> header = new HashMap<String, String>();
header.put("auth-id", prop.getProperty("authid1"));
header.putAll(header());
httpResp=restClient.getResult(prop.getProperty("LoginURL"), header);
//Status code Json String & Headers
JSONObject respJson = TestUtil.staCodeJsonStringHeaders(httpResp);
String idValue = TestUtil.getValueByJPath(respJson, "/user/id");
String uidValue = TestUtil.getValueByJPath(respJson, "/user/uid");
String locationValue = TestUtil.getValueByJPath(respJson, "/user/location");
System.out.println("Value of type : "+idValue);
System.out.println("Value of date : "+uidValue);
System.out.println("Value of date : "+locationValue);
Assert.assertEquals(Integer.parseInt(idValue), 319);
Assert.assertEquals(Integer.parseInt(uidValue), 20190807);
Assert.assertEquals(locationValue, "bangalore");
}
I believe you are using Testng
option 1- using dataprovider
for example
#DataProvider(name = "data-provider")
public Object[][] dataProviderMethod() {
return new headers[][] { { "data1" }, { "data1" } };
}
#Test(dataProvider = "data-provider")
public void GetLoginAPI(String header) throws ClientProtocolException, IOException, JSONException {
// Now use multiple header for GET request
}
Option 2-
Use Hash map to store header and add a loop and use it
HashMap<Integer, String> headervalues = new HashMap<Integer, String>();
headervalues.add("data 1)
headervalues.add("data 2) etc
and then using loop you can use multiple headers.
Option 3-
Using Excel use apacahe POI and then write down readExcel function and pass those values to your script.
Refer https://www.javatpoint.com/how-to-read-excel-file-in-java

Is there a way to send multiple types of HashMap parameters through Ajax in Android Studio?

I'm a beginner at Android Studio and I'm using Ajax to send data to my database server.
I have two types of HashMap parameters that I need to query. One is for all the String values in my form and the other is for the image file but I can't seem to send them in a single call to the new Aquery.ajax(//parameters) method. All the variations of this method limit the use of only one Map type.
I tried putting the ParamFile parameter in a different query but it still doesn't work. Though it could be because I'm not completely sure what an "Object Handler" means here in the other method definition.
Here is the code for my method:
private void AddNewEquipment()
{
try {
//Two types of HashMap files
HashMap<String, String> param = new HashMap<>();
HashMap<String, Bitmap> paramFile = new HashMap<>();
param.put("listing_title", ETitle.getText().toString());
param.put("listing_type", String.valueOf(IntEquipmentType));
param.put("listing_desc", EDesc.getText().toString());
param.put("listing_rate", ERate.getText().toString());
param.put("listing_mode", Mode);
paramFile.put("listing_img_file", bitmap); //this never gets queried
param.put("listing_date_from-x", AvailableFromDT);
param.put("listing_date_to-x", AvailableToDT);
param.put("listing_sell_mode", SellMode);
param.put("listing_display_mode", String.valueOf(IntAdType));
param.put("listing_status", String.valueOf(IntAdStatus));
AQuery aq = new AQuery(this);
aq.ajax(BASE_URL, param, JSONObject.class, new AjaxCallback<JSONObject>() {
#Override
public void callback(String url, JSONObject json, AjaxStatus status) {
super.callback(url, json, status);
Log.v("CALLBACK RECEIVED", String.valueOf(json) + status);
try {
if (json != null) {
JSONObject h = json.getJSONObject("success");
Log.v("SUCCESS", "DONE");
Toast.makeText(AddEquipment.this, "New Equipment Added", Toast.LENGTH_LONG).show();
exitEquipmentForm(); //method that opens the main activity again
} else {
Log.v("ERROR", "ERROR");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.method(AQuery.METHOD_POST).header("Authorization", "Bearer "+SessionHandler.getKeyToken()));
} catch (Exception e) {
e.printStackTrace();
}
}
I keep getting null JSON objects, although that is because not all parameters get queried <---The part where I need help with.
I'm happy to provide more snippets of my code. Please let me know of any alternatives as well.
If you are initializing HashMap with fixed data type then you can not store any other values for that other then specified datatype. If you want to store any data as a value then you should use Object data type.
Like
HashMap<String, Object> param = new HashMap<>();
Then after you can add any value (Bitmap or String) as a Map value.
You can store the value like,
HashMap<String, Object> param = new HashMap<>();
param.put("listing_title", ETitle.getText().toString()); // String values
// add Other String parameters here..
param.put("listing_img_file", bitmap); // Your Image Bitmap file
My suggestion is replace your HashMap<String, Object> with LinkedHashMap<String, Object>. HashMap doesn't maintain any order while LinkedHashMap maintains insertion order of elements.
Try using Object as your value type:
HashMap<String, Object> params = new HashMap<>();

Get AWS Cognito user ID in Serverless Java function

I am following the https://serverless-stack.com/ tutorial which uses the Serverless framework to create an API that inserts objects into a DynamoDB table and associates them to the authenticated AWS Cognito user. I am attempting to convert the Node.js code to Java but I have hit a problem when getting the Cognito identity as shown on this page
userId: event.requestContext.identity.cognitoIdentityId,
I expected the following lines of Java code to be equivalent:
final CognitoIdentity identity = context.getIdentity();
final String userId = identity.getIdentityId();
but userId is empty.
I am using the aws-api-gateway-cli-test utility to call my API with credentials of a Cognito user as shown on this page. The authentication passes but the userId is empty in the handler.
This is my function:
package com.mealplanner.function;
import java.util.Map;
import com.amazonaws.services.lambda.runtime.CognitoIdentity;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mealplanner.dal.MealRepository;
import com.mealplanner.domain.Meal;
import com.serverless.ApiGatewayResponse;
public class CreateMealHandler implements RequestHandler<Map<String, Object>, ApiGatewayResponse> {
#Override
public ApiGatewayResponse handleRequest(final Map<String, Object> request, final Context context) {
try {
final CognitoIdentity identity = context.getIdentity();
final String userId = identity.getIdentityId();
final JsonNode body = new ObjectMapper().readTree((String) request.get("body"));
final MealRepository repository = new MealRepository();
final Meal meal = new Meal();
meal.setUserId(userId);
meal.setDescription(body.get("description").asText());
repository.save(meal);
return ApiGatewayResponse.builder()
.setStatusCode(200)
.setObjectBody(meal)
.build();
} catch (final Exception e) {
final String errorText = String.format("Error saving meal with request [%s]", request);
LOGGER.error(errorText, e);
return ApiGatewayResponse.builder()
.setStatusCode(500)
.setObjectBody(errorText)
.build();
}
}
}
And this is the function definition in serverless.yml:
createMeal:
handler: com.mealplanner.function.CreateMealHandler
events:
- http:
path: /meals
method: post
cors: true
authorizer: aws_iam
Am I missing some configuration or have I not translated the Node.js code correctly?
In case I have missed any pertinent information the full code is available here: https://github.com/stuartleylandcole/meal-planner/tree/add-users. I will update this question with anything that is missing to ensure all relevant information is self-contained.
It turns out I hadn't translated the Node.js code correctly. To access the CognitoIdentityId I had to get the requestContext from the request object, then get the identity object, like so:
public ApiGatewayResponse handleRequest(final Map<String, Object> request, final Context context) {
final Map<String, Object> requestContext = (Map<String, Object>) request.get("requestContext");
final Map<String, Object> identity = (Map<String, Object>) requestContext.get("identity");
final String userId = (String) identity.get("cognitoIdentityId");
// etc
}

How to use termVector in solrJ

Solr/SolrJ Version: 6.0.0
I've set termvector component in solrconfig.xml, and the request handler is "/tvrh", I test it in the browser and this works. Now I want to use it in solrJ, but it only returns the document. The following is my code:
SolrClient solrClient = new HttpSolrClient("http://localhost:8983/solr/test");
SolrQuery solrQuery = new SolrQuery();
solrQuery.setQuery(String.format("id:%s","clueweb12-0000tw-06-17744"));
solrQuery.setRequestHandler("/tvrh");
solrQuery.set("tv", true);
solrQuery.set("tv.all", true);
QueryResponse response = solrClient.query(solrQuery);
SolrDocumentList docs = response.getResults();
for (SolrDocument doc: docs){
for (String key: doc.keySet()){
System.out.println(key);
System.out.println(doc.getFieldValue(key));
}
}
Your question is how to use a non standard request handler in solr.
Be aware that the Term Vector Component belongs to a "non standard" request handler and is not supported from solrj:
https://cwiki.apache.org/confluence/display/solr/The+Term+Vector+Component#TheTermVectorComponent-SolrJandtheTermVectorComponent
You can call "/tvrh" via solrj in a generic mode. You can not use the method SolrClient#query(SolrParams params) for this, because in this case the "request handler" is only send as "qt"-Parameter and will not be part of the url-path (and qt-Parameter is ignored by default).
So please try the method "SolrClient#request" instead.
As #Karsten R says, we could not use SolrClient.query to send request. After I searched a lot and experimented a lot, the following code could work.
SolrClient solrClient = new HttpSolrClient("http://localhost:8983/solr/trecB13");
SolrQuery solrQuery = new SolrQuery();
solrQuery.setQuery(String.format("id:%s","clueweb12-0000tw-06-17744"));
solrQuery.setRequestHandler("/tvrh");
solrQuery.set("tv", true);
solrQuery.set("tv.all", true);
try {
NamedList<Object> response = solrClient.request(new QueryRequest(solrQuery));
TermVectorExtractor extractor = new TermVectorExtractor(response);
System.out.println(extractor.getTermVectorInfo());
} catch (Exception e) {
e.printStackTrace();
}
TermVectorExtractor.java reference Sakai-Solr Github code, the function of the class is to parse resonse object and get term info. A little different from original code. The different has been shown below.
import org.apache.solr.common.util.NamedList;
import java.util.*;
public class TermVectorExtractor {
private static final String TERM_VECTORS = "termVectors";
private Map<String, Map<String, Map<String, TermInfo>>> termVectorInfo = Collections.emptyMap();
/**
* Creates a TermVectorExtractor for the given query response sent by Solr.
*
* #param queryResponse response sent by the solr server for a search query.
*/
#SuppressWarnings("unchecked")
public TermVectorExtractor(NamedList<Object> queryResponse) {
NamedList<Object> res = (NamedList<Object>) queryResponse.get(TERM_VECTORS);
if (res != null)
termVectorInfo = extractTermVectorInfo(res);
}
}

Categories