I'm trying to run a mapReduce query on Riak 1.4 that queries by secondary index, sorts the records by date, and then limits the results to the first record.
I've got the secondary index query working. The sort doesn't seem to do anything. No errors on the sort, just returns the results unsorted. The limit on the number of records returned yields a 'bad_json' error returned by the server.
Here's what I have. It is suppose to query the "cars" bucket for the most recent car owned by "john_doe". (some names have been changed to protect the innocent;) :
JSSourceFunction dateSortFunction = new JSSourceFunction(
"function(v) {" +
"return v.sort(function(a, b) {" +
"return a.issueDate - b.issueDate ;" +
"}" +
");" +
"}");
IndexQuery iq = new BinValueQuery(BinIndex.named("person"), "cars", "john_doe");
MapReduceResult response = session.mapReduce(iq)
.addMapPhase(NamedErlangFunction.MAP_OBJECT_VALUE)
.addReducePhase(dateSortFunction)
.addReducePhase(new NamedJSFunction("Riak.reduceLimit"), 1)
.execute();
I've seen a number of posts on sorting and am hoping to figure it out eventually. However, I haven't seen any help on how the LIMIT function might work.
Thanks in advance!
Update:
Thanks to Joe, he put me on the right track. Here's what ended up working for me. My date format is ISO 8601 (eg. 2011-05-18T17:00:00-07:00). So, I can lexically compare for the correct sorting. Also, I found javascript's array shortening method and updated the code to return up-to the first 5 objects.
JSSourceFunction sortLimitFunction = new JSSourceFunction(
"function(v) {" +
"v.sort(function(a, b) {" +
"return a.issueDate < b.issueDate" +
"}" +
");" +
"if (v.length > " + "5" + ") { " +
"v.length = " + "5" + ";" +
"}" +
"return v;" +
"}");
IndexQuery iq = new BinValueQuery(BinIndex.named("person"), "cars", "john_doe");
MapReduceResult response = session.mapReduce(iq)
.addMapPhase(new NamedJSFunction("Riak.mapValuesJson"))
.addReducePhase(sortLimitFunction)
.execute();
For the sorting, there is a mailing list post that covers this topic. The main difference I see between that implementation and yours is the use of the JavaScript Riak.mapValuesJson function in the map phase.
For the limiting, if you want just the first item from the sorted list, try having your sort function return only the first element. While the reduce function can (and probably is) called multiple times as partial result sets arrive from the various vnodes, the first element in the consolidated list must also be the first element in the partial list where it originated, so this should give you what you are looking for:
JSSourceFunction dateSortFunction = new JSSourceFunction(
"function(v) {" +
"var arr = v.sort(function(a, b) {" +
"return a.issueDate - b.issueDate ;" +
"}" +
");" +
"if (arr.length == 0) { " +
"return [];" +
"} else {"
"return arr[0];" +
"}"
"}"
);
Related
So I am testing the controller of my application and I stumbled upon a problem.
This is the Json I use in my testcode:
String bike = "{" +
" \"bikeNumber\" : \"E2\"," +
" \"brand\" : \"Gazelle\"," +
" \"frameNumber\" : \"HA1234568\"," +
" \"retailPrice\" : 1200," +
" \"basePrice\" : 20.0," +
" \"electric\" : true" +
"}";
I want to test when the user doesn't fill in one of the values, it throws an exception. In other words I want to test the #NotNull, #NotBlank annotations.
I have done this for bikeNumber and frameNumber, these are string types and I can leave them open. The problem I get if I leave the basePrice open and run my test, I get an error saying:
java.lang.AssertionError: No value at JSON path "$.basePrice"
I know that it's a null value because I haven't filled it in, but that is part of the plan. So my question is, how do I leave a long, double or int value empty without getting a test error.
My full code block is here:
#Test
void whenPostRequestNoBasePrice_thenBadRequestResponse() throws Exception {
String bike = "{" +
" \"bikeNumber\" : \"E1\"," +
" \"brand\" : \"Gazelle\"," +
" \"frameNumber\" : \"HA1234568\"," +
" \"retailPrice\" : 1200," +
" \"basePrice\" : \"\" " +
" \"electric\" : true" +
"}";
mockMvc.perform(MockMvcRequestBuilders.post("/createbike")
.content(bike)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.basePrice", Is.is( "Base price is mandatory.")))
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)).andReturn().getResponse().getContentAsString();
}
I tried multiple things, also with and without the comma: "basePrice" : "" ," +
Also I can't seem to find this anywhere on stackoverflow.
This could be a duplicate question, but I couldn't find my solution anywhere. Hence, posting it.
I am trying to simply POST a request for a Student account Creation Scenario. I do have a JSON file which comprises all the "Keys:Values", required for Student account creation.
This is how the file student_Profile.json looks like:
{
"FirstName":"APi1-Stud-FN",
"MiddleInitial":"Q",
"LastName":"APi1-Stud-LN",
"UserAlternateEmail":"",
"SecretQuestionId":12,
"SecretQuestionAnswer":"Scot",
"UserName":"APi1-stud#xyz.com",
"VerifyUserName":"APi1-stud#xyz.com",
"Password":"A123456",
"VerifyPassword":"A123456",
"YKey":"123xyz",
"YId":6,
"Status":false,
"KeyCode":"",
"SsoUserName":"APi1-stud#xyz.com",
"SsoPassword":"",
"BirthYear":2001
}
So everything on Posting the request from "Rest Assured" point of view looks fine, it's just that I want to update a few values from the above JSON body using JAVA so that I can create a new Student profile every time I run my function and don't have to manually change the Body.
For Every POST Student Account Creation scenario, I need to update the value for
the following keys so that a new test student user account can be created:
First Name
Last Name and
Username // "VerifyUserName" and "SSO UserName" will remain same as user name
I modified the answer to get random values and pass them to json body. random value generation was taken from the accepted answer of this question.
public void testMethod() {
List<String> randomValueList = new ArrayList<>();
for (int i = 0; i < 3; i++) {
String SALTCHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
StringBuilder salt = new StringBuilder();
Random rnd = new Random();
while (salt.length() < 18) { // length of the random string.
int index = (int) (rnd.nextFloat() * SALTCHARS.length());
salt.append(SALTCHARS.charAt(index));
}
randomValueList.add(salt.toString());
}
String jsonBody = "{\n" +
" \"FirstName\":\"" + randomValueList.remove(0) + "\",\n" +
" \"MiddleInitial\":\"Q\",\n" +
" \"LastName\":\"" + randomValueList.remove(0) + "\",\n" +
" \"UserAlternateEmail\":\"\",\n" +
" \"SecretQuestionId\":12,\n" +
" \"SecretQuestionAnswer\":\"Scot\",\n" +
" \"UserName\":\"" + randomValueList.remove(0) + " \",\n" +
" \"VerifyUserName\":\"APi1-stud#xyz.com\",\n" +
" \"Password\":\"A123456\",\n" +
" \"VerifyPassword\":\"A123456\",\n" +
" \"YKey\":\"123xyz\",\n" +
" \"YId\":6,\n" +
" \"Status\":false,\n" +
" \"KeyCode\":\"\",\n" +
" \"SsoUserName\":\"APi1-stud#xyz.com\",\n" +
" \"SsoPassword\":\"\",\n" +
" \"BirthYear\":2001\n" +
"}";
Response response = RestAssured
.given()
.body(jsonBody)
.when()
.post("api_url")
.then()
.extract()
.response();
// Do what you need to do with the response body
}
We can used pojo based approach to do certain things very easily . No matter how complex is the payload , serialization and dieselization is the best answer . I have created a framework template for api automation that can we used by putting required POJO's in path :
https://github.com/tanuj-vishnoi/pojo_api_automation
To create pojo, I also have ready to eat food for you :
https://github.com/tanuj-vishnoi/pojo_generator_using_jsonschema2pojo
for the above problem you can refer to the JsonPath lib https://github.com/json-path/JsonPath and use this code:
String mypayload = "{\n" +
" \"FirstName\":\"APi1-Stud-FN\",\n" +
" \"MiddleInitial\":\"Q\",\n" +
" \"LastName\":\"APi1-Stud-LN\"}";
Map map = JsonPath.parse(mypayload).read("$",Map.class);
System.out.println(list);
once the payload converted into map you can change only required values as per the requirement
To generate random strings you can refer to lib org.apache.commons.lang3.RandomStringUtils;
public static String generateUniqueString(int lenghtOfString){
return
RandomStringUtils.randomAlphabetic(lenghtOfString).toLowerCase();
}
I recommend to store payload in a separate file and load it at runtime.
I have a java virtual user script that is sending a payload request. I am trying to use values from a file to send via a loadrunner file parameter.
here is the payload:
private static final String PAYLOAD =
"<ips_cad_mdt>\n" +
" <SignOnRequest>\n" +
" <DestApplication>hhhh</DestApplication>\n" +
" <OrigApplication>hhh</OrigApplication>\n" +
" <SessionRef>3</SessionRef>\n" +
" <Aliasing>1234</Aliasing>\n" +
" </SignOnRequest>\n" +
"</ips_cad_mdt>";
I would like to use something like the following:
private static final String PAYLOAD =
"<ips_cad_mdt>\n" +
" <SignOnRequest>\n" +
" <DestApplication>hhh</DestApplication>\n" +
" <OrigApplication>hhh</OrigApplication>\n" +
" <SessionRef>3</SessionRef>\n" +
" <Aliasing>”+lr.eval_string(“{AliasId}”)+”</Aliasing>\n" +
" </SignOnRequest>\n" +
"</ips_cad_mdt>";
for some reason i cant see any output for this value. do i need to declare a variable: e.g. lr.save_string("AliasId", "{AliasId}");
an example of this would help loads. Many Thanks
There seems to be an error in the code completion in VuGen. The parameters should be reversed and without the {} in save_string.
lr.save_string("1234","myId");
lr.message(lr.eval_string("{myId}"));
In the documentation it is correct - https://admhelp.microfocus.com/lr/en/12.55/help/function_reference/FuncRef.htm#FuncRef/c_vuser/lrFr_lr_save_string.htm?Highlight=lr_save_string
I asked the responsible team to fix the code completion in VuGen so you will be able to see this change in one of the future releases.
I've got an application that executes a lot of javascript server side and I'm trying to convert from Rhino to Nashorn but I am running into trouble with my scripts. Using Rhino I would always convert whatever arguments I had for a function into a JSON string but that's really slow. With Nashorn I'm trying to just pass in the arguments as Java objects but they don't seem to inherit functions from Javascript's Object type. Here is a sample method that illustrates my problem where hasOwnProperty is not available on my array:
public String printArrayValues() throws ScriptException, NoSuchMethodException {
String script =
"function printArrayValues(objArray) {\n" +
" var result = '';\n" +
" for(var obj in objArray) {\n" +
" if(objArray.hasOwnProperty(obj)) {\n" +
" result = result + ' ' + objArray[obj];\n" +
" }\n" +
" }\n" +
" return result;\n" +
"}";
List<String> data = Arrays.asList(new String[]{ "one", "two", "three"});
ScriptEngine scriptEngine = new NashornScriptEngineFactory().getScriptEngine();
scriptEngine.eval(script);
String result = (String) ((Invocable) scriptEngine).invokeFunction("printArrayValues", data);
}
Here the call to invokeFunction throws an exception:
javax.script.ScriptException: TypeError: [one, two, three] has no such function "hasOwnProperty" in <eval> at line number 4
If I call the same function in a browser, I get what I would expect:
> printArrayValues(["one", "two", "three"]);
> " one two three"
Is there some way I can accomplish this so I really can use these Java objects without turning them into a JSON string and then eval'ing it into a Javascript object?
You can't use Java arrays in this way. Java arrays are "hardwired" objects. Unlike ordinary objects, they don't have methods and they support the [] operator, which objects can't.
This Article about Nashorn at Oracle explains that you need to use the Java.to and Java.from methods in your javascript in order to change a Java array to a Javascript array.
use Java.from() to transform the Java List to Javascript Array, and then operate on it.
String script =
"function printArrayValues(objArray) {\n" +
" var result = '';\n var temp = Java.from(objArray);" +
" for(var obj in temp ) {\n" +
" if(temp .hasOwnProperty(obj)) {\n" +
" result = result + ' ' + temp [obj];\n" +
" }\n" +
" }\n" +
" return result;\n" +
"}";
I have this statement:
s = s + "Id: " + lc.getID() + " Name: " + lc.getName() + "\n"
+ " Phone Number: " + lc.getPhone() + " Email: " + lc.getEmail() + "\n"
+ " Description: " + lc.getDescription() + "\n\n"
that prints this out:
Id: 1 Name: Eric
Phone Number: 8294038 Email: foo#gmail.com
Description: Cool guy Eric
I want to Bold only the titles (Id, Name, etc).
I tried this:
s = s + Html.fromHtml(" <b> Id: </b>" + lc.getID() + " <b> Name: </b>" + lc.getName() + "\n"
+ " Phone Number: " + lc.getPhone() + " Email: " + lc.getEmail() + "\n"
+ " Description: " + lc.getDescription() + "\n"
+ "\n\n");
But not only does it not bold, but it takes away the new lines (\n). Any ideas on how to get this done? Thanks.
Html.fromHtml() returns a Spanned object, designed to be put directly into a TextView or similar widget.
A Spanned is not a String.
By doing s = s + Html.fromHtml(...), you are saying "please parse this HTML into a Spanned, then throw out all the formatting to give me a String that I can concatenate onto some other String". That's not what you want -- you want to keep the formatting. But a Java String does not have formatting, and so ordinary string concatenation has no way to keep it.
Beyond that, as Manishika pointed out, newlines are ignored in HTML anyway, as you use HTML elements for vertical whitespace.
Your options include:
Generate a complete HTML snippet -- including whatever it is you are trying to concatenate it to -- and then use Html.fromHtml() on the entire thing. You may wish to use a template engine (e.g., jmustache) for that, or String.format(). Or, use StringBuilder, rather than lots of + operations (less memory churn, faster performance). Be sure to use <br/> or <p> for your line breaks/paragraph delimiters.
Use SpannableStringBuilder to assemble the string and its formatting from component parts.
Use TextUtils.concat(s, Html.fromHtml(...)) instead of s + Html.fromHtml(...), as concat() will maintain the spans that implement the formatting. While the implementation of Spanned returned by fromHtml() is not a String, both it and String are a CharSequence, and hence work with concat().
It will require a little bit of parsing on your end, but you definitely want to look into SpannableStrings.
For example, let's say I have the following string:
String s = "How now brown cow";
I would then turn it into a SpannableString by simply feeding the string to the constructor as follows:
SpannableString ss = new SpannableString(s);
From there you need your stylization with the spanned area. For this, I'll just use SubscriptSpan, though if you wish to make your own you can simply make your own class extending CharacterStyle and override the updateDrawState(TextPaint ds) method. The following is how you can set you span:
/ *
* the first argument is the span effect you want, the second and third
* are the start and end indices, respectively, and the last argument is
* for setting a flag, which you probably won't need.
*/
ss.setSpan(new SubscriptSpan(), 0, 2, 0);
And now you can just put your string straight into the TextView and it should appear how you want, like so:
myTextView.setText(ss);