How to test a Datastream with jsonobject in Apache Flink - junit

I am new to testing and i am trying to write a unit test cases on a Flink Datastream which takes input a jsonobject and passes the json object to a processfuntion and it returns a valid or invalid jsonobject when certain rule conditions are met below is the junit test case, below i am trying to compare the output jsonobject from process function with the jsonobject of the input file
#Test
public void testcompareInputAndOutputDataJSONSignal() throws Exception {
org.json.JSONObject jsonObject = toJsonObject();
String input = jsonObject.toString();
String output = JSONDataStreamOutput();
assertEquals(mapper.readTree(input), mapper.readTree(output));
}
below is my toJSONObject and JSONDataStream meathods
public static JSONObject toJsonObject() throws IOException, ParseException {
JSONParser jsonParser = new JSONParser();
FileReader fileReader = new FileReader(getFileFromResources("input.json"));
JSONObject obj = (JSONObject) jsonParser.parse(fileReader);
return obj;
}
public String SignalDataStreamOutput() throws Exception {
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream<JSONObject> validSignal = env.fromElements(toJsonObject())
.process(new JsonFilter());
String outputFolder = "output";
validSignal.writeAsText(outputFolder).setParallelism(1);
env.execute();
String content = new String(Files.readAllBytes(Paths.get("output.txt")));
return content;
}
What i am doing is i am converting a jsonfile to jsonobject using the toJSONObject method and sending to a data stream using SignalDataStreamOutput method which will intern send it to a process function in JsonFilter class and validate it against a set of rules and if it's valid it will return a jsonobject and when trying to access the jsonobject directly from stream i am getting value like org.apache.flink#994jdkeiri so i am trying to write the output to a file and trying to read it back to a string and comparing it in test method but this is a work around process and i found a link to use Mockito framework here i changed it to use json object like below
final Collector<JSONObject> collectorMock = (Collector<JSONObject>)Mockito.mock(JsonFilter.class);
final Context contextMock = Mockito.mock(Context.class);
#Test
public void testcompareInputAndOutputDataForValidSignal() throws Exception {
org.json.JSONObject jsonObject = convertToJsonObject();
Mockito.verify(collectorMock).collect(jsonObject);
}
but the above approach is also not working can you suggest me simplified approach to test the json object

Related

Spring - Return Raw JSON without double serialization

I know there are other posts similar to this, but I haven't found any that help me find a solution for this particular case.
I am trying to return a HashMap<String, Object> from my Controller.
The Object part is a JSON string, but its being double serialized and not returned as a raw JSON string, thus not ending up with extra quotations and escape characters.
Controller function:
#RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public HashMap<String, Object> heartbeat(){
String streamInfo = service.getStreamInfo();
String streamCursorInfo = service.getStreamCursorInfo();
String topicInfo = service.getTopicInfo();
String greeting = "This is a sample app for using Spring Boot with MapR Streams.";
HashMap<String, Object> results = new HashMap();
results.put("greeting", greeting);
results.put("streamInfo", streamInfo);
results.put("streamCursorInfo", streamCursorInfo);
results.put("topicInfo", topicInfo);
return results;
}
Service function:
private String performCURL(String[] command){
StringBuilder stringBuilder = new StringBuilder();
try{
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process p = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while((line = reader.readLine()) != null){
stringBuilder.append(line);
}
}
catch(Exception e){
LOGGER.error(ExceptionUtils.getRootCauseMessage(e));
}
return stringBuilder.toString();
}
The cURL command I run already returns a raw JSON string. So im just trying to add it to the HashMap to be returned in the heartbeat response.
But every time I run this, my output looks like:
{
"greeting": "This is a sample app for using Spring Boot with MapR Streams.",
"streamCursorInfo": "{\"timestamp\":1538676344564,\"timeofday\":\"2018-10-04 02:05:44.564 GMT-0400 PM\",\"status\":\"OK\",\"total\":1,\"data\":[{\"consumergroup\":\"MapRDBConsumerGroup\",\"topic\":\"weightTags\",\"partitionid\":\"0\",\"produceroffset\":\"44707\",\"committedoffset\":\"10001\",\"producertimestamp\":\"2018-10-03T05:57:27.128-0400 PM\",\"consumertimestamp\":\"2018-09-21T12:35:51.654-0400 PM\",\"consumerlagmillis\":\"1056095474\"}]}",
...
}
If i return only the single string, such as streamInfo then it works fine and doesnt add the extra quotes and escape chars.
Can anyone explain what im missing or need to do to prevent this double serialization?
Instead of returning a HashMap, create an object like this:
public class HeartbeatResult {
private String greeting;
... //other fields here
#JsonRawValue
private String streamCursorInfo;
... //getters and setters here (or make the object immutable by having just a constructor and getters)
}
With #JsonRawValue Jackson will serialize the string as is. See https://www.baeldung.com/jackson-annotations for more info.
streamCursorInfo is a string, not an object => the serialization will escape the " character.
If you are able to return the object containing the data, it will work out of the box. If what you have is just a String, I suggest to serialize it to JsonNode and add it in your response
ObjectMapper objectMapper = new ObjectMapper();
JsonNode streamCursorInfo = objectMapper.readTree(service.getStreamInfo())
results.put("streamCursorInfo", streamCursorInfo);

JSON.NET: getting json from external source with streams, how to get just one value?

I have the following code:
static void Main(string[] args)
{
HttpClient client = new HttpClient();
using (Stream stream = client.GetStreamAsync("https://opendata.rdw.nl/resource/8ys7-d773.json?kenteken=61SFSL").Result)
using (StreamReader streamReader = new StreamReader(stream))
using (JsonReader reader = new JsonTextReader(streamReader))
{
JsonSerializer serializer = new JsonSerializer();
// read the json from a stream
// json size doesn't matter because only a small piece is read at a time from the HTTP request
//What do I do here to get my one value?
}
Console.WriteLine("Press any key to continue...");
Console.Read();
}
I got this from the documentation over at the JSON.NET website. The reason being that I don't want to load the whole string, but piece by piece. The response is as follows:
[{"brandstof_omschrijving":"Benzine","brandstof_volgnummer":"1","brandstofverbruik_buiten":"6.60","brandstofverbruik_gecombineerd":"8.20","brandstofverbruik_stad":"11.10","co2_uitstoot_gecombineerd":"196","emissiecode_omschrijving":"Euro 4","geluidsniveau_rijdend":"71","geluidsniveau_stationair":"82","kenteken":"61SFSL","milieuklasse_eg_goedkeuring_licht":"70/220*2001/100B","nettomaximumvermogen":"99.00","toerental_geluidsniveau":"4125"}]
I.e., it returns an array with one json object, and I want to retrieve just one value in there, using a stream. How might I do this?
You could try the following
using System;
using System.Net.Http;
using Newtonsoft;
public class Program {
public static void Main() {
var client = new HttpClient();
var json = client.GetStringAsync("https://opendata.rdw.nl/resource/8ys7-d773.json?kenteken=61SFSL").Result;
var data = JsonConvert.DeserializeObject<dynamic>(json);
string value = data[0].co2_uitstoot_gecombineerd;
Console.WriteLine(value);
Console.WriteLine("Press any key to continue...");
Console.Read();
}
}

How to input a JSON byteCode (txt file) and parse it?

I made a JSON file and the I used FileOutputStream to save it as a text file in my hard drive . Then I use FileinputStream to input the file in a separated class. I use this code to print the JSON , but how can i parse it now using JSONParser .
public static void main(String[] args) throws Exception {
FileInputStream fileInputStream = new FileInputStream("D:\\XmlToJson.txt");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
JSONArray jsonArray = (JSONArray) objectInputStream.readObject();
ObjectInputStream is not the correct class to use here. That is to read Java objects from Java's own serialisation scheme. Has nothing to do with JSON. And why JSONParser if you don't want to parse lazy and use the parse events to build some data structure other than a JSONArray then a JsonReader is the way to go.
Slightly adapted example from the Java documentation:
public static void main(String[] args) throws Exception {
FileInputStream fileInputStream = new FileInputStream("D:\\XmlToJson.txt");
JsonReader jsonReader = Json.createReader(fileInputStream);
JsonArray array = jsonReader.readArray();
jsonReader.close();
// ...
}

Can't read Mocked Java.io.Reader

I want to test following code with Mockito:
public static String funcToTest(String query) throws Exception {
String url = Config.getURL(serviceName);
HttpClient client = new HttpClient();
HttpMethod method = new GetMethod(url);
String resultantString= "";
method.setQueryString(URIUtil.encodeQuery(query));
client.executeMethod(method);
if (method.getStatusCode() == HttpStatus.SC_OK) {
Reader reader = new InputStreamReader(method
.getResponseBodyAsStream());
int charValue = 0;
StringBuffer sb = new StringBuffer(1024);
while ((charValue = reader.read()) != -1) {
sb.append((char) charValue);
}
resultantString = sb.toString();
}
method.releaseConnection();
return resultantString;
}
I created the test like following:
#Test
public void testFunc() throws Exception{
HttpMethod method = Mockito.mock(HttpMethod.class);
InputStream inputStream = Mockito.mock(InputStream.class);
Reader reader = Mockito.mock(Reader.class);
when(method.getResponseBodyAsStream()).thenReturn(inputStream);
PowerMockito.whenNew(Reader.class).withArguments(eq(inputStream)).thenReturn(reader);
Mockito.when(reader.read()).thenReturn((int)'1', -1);
String actualResult = cls.funcToTest("");
String expected = "1";
assertEquals(expected, actualResult);
}
But the reader.read() method is not returning 1. Instead it always returns -1. How should I mock Reader so that read() method will return something else other than -1.
Thanks.
First of all , your test code is doing lots of .class mocking to mock function local variables / references. Mocking is for class dependencies and not for function local variables.
As written, you can't test your function funcToTest with mocking alone. You need to rewrite this function if not willing to use real objects for - HttpMethod & Reader.
You need to remove object creation code with new outside this function if you wish to mock calls on those objects and replace code of new with this get method. e.g.
protected HttpMethod getHttpMethod(String Url){
return new GetMethod(url);
}
Also, I don't see you mocking this line for a fake URL - it seems necessary for unit testing.
String url = Config.getURL(serviceName);
After taking object creation code outside your function, you need to create a new class than extends your SUT ( Subject Under Test ) and you override these methods ( getHttpMethod) to provide fake/mocked instances.
You need to write similar method to get Reader instance.
Then you test this new class - extended from your SUT since object creation logic need not to be tested.
Without taking object creation code outside the function, I don't see a way of mocking it by mockito.
Hope it helps !!
It must work, I'm sorry what make you slightly confused )
// annotations is very important, cls I your tested class name, i assume cls is yours
#RunWith(PowerMockRunner.class)
#PrepareForTest({cls.class})
public class PrinterTest {
#Test
public void print() throws Exception {
String url = "";
GetMethod method = Mockito.mock(GetMethod.class);
InputStream inputStream = Mockito.mock(InputStream.class);
InputStreamReader reader = Mockito.mock(InputStreamReader.class);
Mockito.when(method.getResponseBodyAsStream()).thenReturn(inputStream);
//forgot about it )
PowerMockito.whenNew(GetMethod.class).withArguments(eq(url)).thenReturn(method);
PowerMockito.whenNew(InputStreamReader.class).withArguments(eq(inputStream)).thenReturn(reader);
Mockito.when(reader.read()).thenReturn((int) '1', -1);
when(method.getStatusCode()).thenReturn(HttpStatus.SC_OK);
String actualResult = cls.funcToTest(url);
String expected = "1";
assertEquals(expected, actualResult);
}
}

Encoding collection to json array in jsr 356

I am learning websockets and my webapp is using jsr 356 library. I followed the tutorials and I can encode/decode POJOs, however I can't find examples on how to serialize either arrays or collections to JSON.
This is what I am doing to encode my data:
#Override
public String encode(ScanPlus scan) throws EncodeException {
JsonObject jsonObject = createJsonObject(scan);
return jsonObject.toString();
}
private JsonObject createJsonObject(ScanPlus scan) {
JsonObject jsonObject = Json.createObjectBuilder()
.add("scan", scan.getCode())
.add("creationdate", String.valueOf(scan.getCreationDate()))
.add("username", scan.getUserName())
.build();
return jsonObject;
}
public String encode(ArrayList<ScanPlus> scans) throws EncodeException {
JsonArrayBuilder jsonArray = Json.createArrayBuilder();
for (ScanPlus scan : scans) {
JsonObject jsonObject = createJsonObject(scan);
jsonArray.add(jsonObject);
}
return jsonArray.toString();
}
This is how I send the data to the encoder:
#OnOpen
public void onOpen(Session session, #PathParam("username") String username) {
...
session.getBasicRemote().sendObject(scans);
}
And this is the exception I am getting:
javax.websocket.EncodeException: No encoder specified for object of class [class java.util.ArrayList]
Could anyone give me a hint on how to do it?
thanks
You need to create Encoder<ArrayList<ScanPlus>>; Encoder<ScanPlus> is not enough..