Documentation suggests testing API client based on WSClient using a mock web service, that is, create a play.server.Server which will respond to real HTTP requests.
I would prefer to create WSResponse objects directly from files, complete with status line, header lines and body, without real TCP connections. That would require less dependencies and run faster. Also there may be other cases when this is useful.
But I can't find a simple way to do it. It seems all implementations wrapped by WSResponse are tied to reading from network.
Should I just create my own subclass of WSResponse for this, or maybe I'm wrong and it already exists?
The API for Play seems intentionally obtuse. You have to use their "Cacheable" classes, which are the only ones that seem directly instantiable from objects you'd have lying around.
This should get you started:
import play.api.libs.ws.ahc.AhcWSResponse;
import play.api.libs.ws.ahc.cache.CacheableHttpResponseBodyPart;
import play.api.libs.ws.ahc.cache.CacheableHttpResponseHeaders;
import play.api.libs.ws.ahc.cache.CacheableHttpResponseStatus;
import play.shaded.ahc.io.netty.handler.codec.http.DefaultHttpHeaders;
import play.shaded.ahc.org.asynchttpclient.Response;
import play.shaded.ahc.org.asynchttpclient.uri.Uri;
AhcWSResponse response = new AhcWSResponse(new Response.ResponseBuilder()
.accumulate(new CacheableHttpResponseStatus(Uri.create("uri"), 200, "status text", "protocols!"))
.accumulate(new CacheableHttpResponseHeaders(false, new DefaultHttpHeaders().add("My-Header", "value")))
.accumulate(new CacheableHttpResponseBodyPart("my body".getBytes(), true))
.build());
The mystery boolean values aren't documented. My guess is the boolean for BodyPart is whether that is the last part of the body. My guess for Headers is whether the headers are in the trailer of a message.
I used another way, mocking WSResponse with Mockito:
import play.libs.ws.WSRequest;
import play.libs.ws.WSResponse;
import org.mockito.Mockito;
...
final WSResponse wsResponseMock = Mockito.mock(WSResponse.class);
Mockito.doReturn(200).when(wsResponseMock).getStatus();
final String jsonStr = "{\n"
+ " \"response\": {\n"
+ " \"route\": [\n"
+ " { \"summary\" :\n"
+ " {\n"
+ " \"distance\": 23\n"
+ " }\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ "}";
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = null;
try {
jsonNode = mapper.readTree(jsonStr);
} catch (IOException e) {
e.printStackTrace();
}
Mockito.doReturn(
jsonNode)
.when(wsResponseMock)
.asJson();
If you are using play-framework 2.8.x and scala, the below code can help us generate a dummy WSResponse:
import play.api.libs.ws.ahc.AhcWSResponse
import play.api.libs.ws.ahc.cache.CacheableHttpResponseStatus
import play.shaded.ahc.org.asynchttpclient.Response
import play.shaded.ahc.org.asynchttpclient.uri.Uri
import play.api.libs.ws.ahc.cache.CacheableHttpResponseBodyPart
import play.shaded.ahc.io.netty.handler.codec.http.DefaultHttpHeaders
class OutputWriterSpec extends FlatSpec with Matchers {
val respBuilder = new Response.ResponseBuilder()
respBuilder.accumulate(new CacheableHttpResponseStatus(Uri.create("http://localhost:9000/api/service"), 202, "status text", "json"))
respBuilder.accumulate(new DefaultHttpHeaders().add("Content-Type", "application/json"))
respBuilder.accumulate(new CacheableHttpResponseBodyPart("{\n\"id\":\"job-1\",\n\"lines\": [\n\"62812ce276aa9819a2e272f94124d5a1\",\n\"13ea8b769685089ba2bed4a665a61fde\"\n]\n}".getBytes(), true))
val resp = new AhcWSResponse(respBuilder.build())
val outputWriter = OutputWriter
val expected = ("\"job-1\"", List("\"62812ce276aa9819a2e272f94124d5a1\"", "\"13ea8b769685089ba2bed4a665a61fde\""), "_SUCCESS")
"Output Writer" should "handle response from api call" in {
val actual = outputWriter.handleResponse(resp, "job-1")
println("the actual : " + actual)
actual shouldEqual(expected)
}
}
Related
I'm setting up my Pepper-Box Plain text Config to Pass variable using ${accountNumber}, ${{accountNumber}}, {{accountNumber}}, and using function to return string, but it didn't work.
This is my message to kafka :
{
"eventName": "OFFER",
"payload": {
"accountNumber": "${accountNumber}",
"Limit": 20000000
}
}
but the variable didn't pass, when I see the debug sampler, the accountNumber is pass.
I think there is mistake when I call the variable, but I try some techniques but it didnt work too.
The error Message when I try ${{accountNumber}} is :
symbol: method accountNumber()
location: class MessageIterator1566802574812
1 error
Uncaught Exception java.lang.ClassFormatError: Truncated class file. See log file for details.
It looks like a limitation of the plugin, you're basically limited to Schema Template Functions
Alternatively you can send a record to Kafka using JSR223 Sampler and the following Groovy code:
import org.apache.jmeter.threads.JMeterVariables
import org.apache.kafka.clients.producer.KafkaProducer
import org.apache.kafka.clients.producer.ProducerRecord
def kafkaProps = new Properties()
kafkaProps.put(org.apache.kafka.clients.producer.ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092")
kafkaProps.put(org.apache.kafka.clients.producer.ProducerConfig.CLIENT_ID_CONFIG, "KafkaExampleProducer")
kafkaProps.put(org.apache.kafka.clients.producer.ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.LongSerializer.class.getName())
kafkaProps.put(org.apache.kafka.clients.producer.ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.StringSerializer.class.getName())
def producer = new KafkaProducer<>(kafkaProps)
JMeterVariables vars = new JMeterVariables()
vars.put("accountNumber", "foo")
def record = new ProducerRecord<>("test", "{\n" +
" \"eventName\": \"OFFER\",\n" +
" \"payload\": {\n" +
" \"accountNumber\": \"" + vars.get("accountNumber") + "\",\n" +
" \"Limit\": 20000000\n" +
" }\n" +
"}")
producer.send(record)
More information: Apache Kafka - How to Load Test with JMeter
I believe I’m seeing different results from a Java-based query and what I believe is the equivalent cts:search in the query console. There's a lot of information here and I tried to organize it appropriately. Here are the steps to set up a simple example that replicates what I’m seeing.
Create new database with default settings
Add new forest with default settings
Enable three character searches (only non-default database setting)
Insert the three json documents below into the database
Query console returns doc2. Java client returns doc2 AND doc1. Why? I would expect the same results from each. I want to get the results in Java that the query console is returning. Am I writing the query definition in Java incorrectly?
It looks like the Java client wildcard search is searching the entire document even though I’ve specified that I only want to do a wildcard search inside of the given json-property (name.)
Is there a way to see or log the resultant server-side “cts query” given a client-side RawCombinedQueryDefinition? I'd like to see what the Java request gets translated into on the server side.
doc1.json
{
"state": "OH",
"city": "Dayton",
"notes": "not Cincinnati"
}
doc2.json
{
"state": "OH",
"city": "Cincinnati",
"notes": "real city"
}
doc3.json
{
"state": "OH",
"city": "Daytona",
"notes": "this is a made up city"
}
Query console code used to insert documents
xquery version "1.0-ml";
xdmp:document-load("/some/path/doc1.json",
<options xmlns="xdmp:document-load">
<uri>/doc1.json</uri>
</options>
);
Query console code used to search
xquery version "1.0-ml";
cts:search(fn:collection(),
cts:and-query((
cts:json-property-value-query("state", "OH"),
cts:json-property-value-query("city", "*Cincinnati*")
))
)
Java QueryManager query in easy to read text
{
"search": {
"query": {
"queries": [
{
"value-query": {
"type": "string",
"json-property": "state",
"text": "OH"
}
},
{
"value-query": {
"type": "string",
"json-property": "city",
"text": "*Cincinnati*"
}
}
]
}
}
}
Java code
import com.marklogic.client.DatabaseClient;
import com.marklogic.client.DatabaseClientFactory;
import com.marklogic.client.document.DocumentPage;
import com.marklogic.client.document.DocumentRecord;
import com.marklogic.client.document.JSONDocumentManager;
import com.marklogic.client.io.Format;
import com.marklogic.client.io.StringHandle;
import com.marklogic.client.query.QueryManager;
import com.marklogic.client.query.RawCombinedQueryDefinition;
import org.junit.Test;
public class MarkLogicTest
{
#Test
public void testWildcardSearch()
{
DatabaseClientFactory.SecurityContext securityContext = new DatabaseClientFactory.DigestAuthContext("admin", "admin");
DatabaseClient client = DatabaseClientFactory.newClient("localhost", 8000, "test", securityContext);
QueryManager queryManager = client.newQueryManager();
JSONDocumentManager documentManager = client.newJSONDocumentManager();
String query = "{\n" +
" \"search\": {\n" +
" \"query\": {\n" +
" \"queries\": [\n" +
" {\n" +
" \"value-query\": {\n" +
" \"type\": \"string\",\n" +
" \"json-property\": \"state\",\n" +
" \"text\": \"OH\"\n" +
" }\n" +
" },\n" +
" {\n" +
" \"value-query\": {\n" +
" \"type\": \"string\",\n" +
" \"json-property\": \"city\",\n" +
" \"text\": \"*Cincinnati*\"\n" +
" }\n" +
" }\n" +
" ]\n" +
" }\n" +
" }\n" +
"}";
StringHandle queryHandle = new StringHandle(query).withFormat(Format.JSON);
RawCombinedQueryDefinition queryDef = queryManager.newRawCombinedQueryDefinition(queryHandle);
DocumentPage documents = documentManager.search(queryDef, 1);
while (documents.hasNext())
{
DocumentRecord document = documents.next();
StringHandle resultHandle = document.getContent(new StringHandle());
String result = resultHandle.get();
System.out.println(result);
}
}
}
System.out.println() results
{"state":"OH", "city":"Dayton", "notes":"not Cincinnati"}
{"state":"OH", "city":"Cincinnati", "notes":"real city"}
Why does the Java client return the first result where city = Dayton?
Thanks in advance!
The REST API and thus the Java API executes an unfiltered search by default (meaning, the matches are based entirely on the indexes). By contrast, cts:search() executes a filtered search by default (meaning, the result documents are inspected to throw out false positives).
If you add the "unfiltered" option to cts:search(), it also returns both documents.
The quick fix is to add the "filtered" option to the Java API search, but the better fix for performance at scale is to refine the indexes to support exact matching for the required wildcard queries.
Elements are correlated with wildcards based on position.
Thus, for this query, I believe you need to turn on the index configurations for element word positions and for three character word positions.
Hoping that helps,
From a quick look at the above code, You do not have the AND query in your java example. Therefore it is an or-query fo Ohio OR Cincinnati.
My Json is:
{
"objects":{
"apple":[
{"x":3, "y":5},
{"x":6, "y":9}
],
"car":[
{"x":7, "y":9},
{"x":5, "y":8}
]
}
}
import com.badlogic.gdx.utils.Json;
import java.util.ArrayList;
import java.util.HashMap;
public class ClassA{
public Integer x, y;
}
public class ClassB{
public HashMap<String, ArrayList<ClassA>> objects;
}
public static void main(String[] args) {
Json json = new Json();
ClassB classB = json.fromJson(ClassB.class, "{\n" +
" \"objects\":{\n" +
" \"apple\":[\n" +
" {\"x\":3, \"y\":5},\n" +
" {\"x\":6, \"y\":9}\n" +
" ],\n" +
" \"car\":[\n" +
" {\"x\":7, \"y\":9},\n" +
" {\"x\":5, \"y\":8}\n" +
" ]\n" +
" }\n" +
" }");
System.out.println(json.toJson(classB));
}
I use "Libgdx", "json.fromJson" is works fine and when i call "json.toJson(classB)" an exception throws:
Exception in thread "main" java.lang.StackOverflowError
at com.badlogic.gdx.utils.JsonWriter$OutputType.quoteValue(JsonWriter.java:187)
at com.badlogic.gdx.utils.JsonWriter.value(JsonWriter.java:88)
at com.badlogic.gdx.utils.Json.writeValue(Json.java:574)
at com.badlogic.gdx.utils.Json.writeFields(Json.java:290)
at com.badlogic.gdx.utils.Json.writeValue(Json.java:580)
at com.badlogic.gdx.utils.Json.writeFields(Json.java:290)
at com.badlogic.gdx.utils.Json.writeValue(Json.java:580)
...
When i change "ArrayList" to String(etc) from HashMap in ClassB the code works fine.
So why an exception is thowing when i use "ArrayList" and how can i parse my json to ClassB instance?
Yes, the StackOverflowException itself is a bug.
The libGDX' JSON class expects class type information in certain places, if it can't deduce the type by itself. In this regard it is much less tolerant than other, much larger libraries such as Gson.
see: https://github.com/libgdx/libgdx/wiki/Reading-%26-writing-JSON#writing-object-graphs
The easiest fix in your example is to write your ClassA instances as:
" {\"class\": \"net.your.package.ClassA\", \"x\":3, \"y\":5},\n"
The class name can be shortened, see Json.setElementType().
In general, as a best practice, for prototyping I recommend the opposite to your approach. Create the structure in code, then write to JSON to see how libGDX "perceives" your data structure, then read back from JSON to verify the output.
Side note: for most cases its recommended to use the libGDX containers, ObjectMap<> and Array<> in your example. Also, ClassA members can probably be int instead of Integer to avoid auto-boxing.
As requested in the comments.
Post the libGDX bug as a new issue here.
add this to your build.gradle dependencies (to the core project if you use the default structure):
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0'
Initialize a Gson object:
Gson gson = new Gson();
And use the from and to json functions:
String json = gson.toJson(classB);
and
ClassB classB = gson.fromJson(json,ClassB.class);
This question already has answers here:
How can I upload files to a server using JSP/Servlet and Ajax?
(4 answers)
Closed 6 years ago.
I am trying send an bitmap and some string fields to server, and I have checked thoroughly no parameter is empty. This is my ajax code
var URL = "ProfileUpdater";
var username = $("#cp-setup-username").val();
var email = $("#cp-setup-email").val();
var birthday = $("#cp-setup-birthday").val();
var aboutYou = $("#cp-setup-about-you").val();
var intrests = $("#cp-setup-intrests").val();
var phoneNumber = $("#cp-setup-phone-number").val();
var sessionid = $.cookie('WhitePages_SessionID');
var session_username = $.cookie('WhitePages_Username');
var legal = emptyCheck(username,email,birthday,aboutYou,intrests,phoneNumber);
alert(username +" " + email + " " + birthday +" " + aboutYou + " " +intrests + " " + phoneNumber +" "+ sessionid +" " + session_username);
alert(result);
if(legal){
alert(sessionid + " " + session_username) ;
alert("about call server");
$.ajax({
type:'POST',
url : URL,
processData:'false',
contentType:'false',
data:{Username:username,Email:email,Birthday:birthday,AboutYou:aboutYou,Intrests:intrests,PhoneNumber:phoneNumber,sessionid:sessionid,username:session_username,Image:result,FieldsChanged:fieldsChanged,isMultiPart:isMultiPart},
success:function(data){
alert("success");
alert(data);
}
});
}
and this is my servlet code:
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ProfileUpdater extends HttpServlet {
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String user = request.getParameter("Username");
String sessionid = request.getParameter("sessionid");
String username = request.getParameter("username");
//sessionid and username is null
PrintWriter out = response.getWriter();
out.println(sessionid +" " + username + " " + user);
System.out.println("hello " + username + "your session id is " +sessionid + " " + user );
}
}
I have put alerts in my script and they are not empty but on response it's null. I mean I think it's sending null to server. Can someone please tell me where I am going wrong ??? Thankyou.
You can't use getParameter() with a multipart post. It just returns null as you discovered. Depending on which servlet spec you are coding to, you can either use the #MultipartConfig annotation (spec 3.0+), or the Apache Commons FileUpload library. The annotation method is built-in, but requires a bit more work; the FileUpload library is easier to use IMO, but obviously requires including another library. I'm not sure which is more efficient in terms of resources or speed. Interestingly if you're using Tomcat it uses FileUpload to handle things in the background anyway.
I am making a post request with the libraries listed below. It seems like my last header is being cut off. Ive tried the following two ways but neither seems to be working.
import scalaj.http._
import scalaj.http.Http
var result = Http("https://example.com" + Key + "/rowset")
.postData(jsonOutput)
.headers(Seq("Authorization" -> ("Bearer " + accessToken)))
.headers(Seq("content-Type" -> "application/json"))
var result = Http("https://example.com" + Key + "/rowset")
.postData(jsonOutput)
.headers(Seq("Authorization" -> ("Bearer " + accessToken), "content-Type" -> "application/json"))
Just to check; you are doing something with the result variable? It is still just a request and will remain so until you call i.e. result.asString which will execute the request and return the response (HttpResponse[String] in case of asString).