We have some intergation tests over #RestController with a common pattern to verify that an Xpath expression exists and that an Http header is set. But I would like to go further and verify that the XPath value is equald or contained into the header.
mvc.perform(..)
.andExpect(xpath("Item/#id/").isIn(header("Location")))
Is it something for that or should I create my own ResultMatcher ?
org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath(xpathExpress, args) is what you want.
For example:
ResultActions resultActions = mvc.perform(..);
String location = resultActions.andReturn().getResponse().getHeader("Location");
resultActions.andExpect(MockMvcResultMatchers.xpath("Item/#id/", null)
.string(org.hamcrest.Matchers.containsString(location)));
If you need to compare by Node, XMLUnit for Java 2.x offers more usefule Matcher.
Related
I want to test an endpoint using jmeter, that has a copule of query string parameters, one of which is optional, loading the values from a CSV file. The problem is, can I avoid sending the query string parameter if I don't have a value for it?
It is but it will require some Groovy coding
Add JSR223 PreProcessor as a child of the request which query string you want to modify (or according to JMeter Scoping Rules if you want to apply the approach to more than one request)
Put the following code into "Script" area:
def newData = new org.apache.jmeter.config.Arguments()
0.upto(sampler.getArguments().size() - 1, { idx ->
def arg = sampler.getArguments().getArgument(idx)
if (!arg.getValue().equals('')) {
newData.addArgument(arg)
}
})
sampler.setArguments(newData)
That's it, the PreProcessor will be executed before the HTTP Request sampler and will remove all arguments which don't have their respective values
I have following request parameters.
a
b
c
d
e
f
Request can contain all the parameters or some of them. I am currently using regex /** to resolve this.
Is there any way to explicitly mention the request mapping instead ** and say it is optional. And any order also should match.
/a/1/b/f2
and
/b/f2/a/1
Both should match that mapping.
There is no way to achieve this via #PathVariable's. If you want the flexibility of random order & number of path variables. You can just do the following;
#GetMapping("/myEndpoint/**")
public void theEndpoint(HttpServletRequest request) {
String requestURI = request.getRequestURI();
Stream.of(requestURI.split("myEndpoint/")[1].split("/")).forEach(System.out::println);
}
You can put a .filter(StringUtils::isNotBlank) in case /myEndpoint/a///b/c
Will give you
a
1
b
f2
d
x
when you call /myEndpoint/a/1/b/f2/d/x
b
f2
1
when you call /myEndpoint/b/f2/1
Also, be aware that you'd need some anchor base in your endpoint, e.g. /myEndpoint. Otherwise all your other endpoints will be conflicted with this endpoint.
ps. Better to use request params for such inputs tbh, not sure your requirement here, but just FYI. It is not the best to have such a hacky structure really...
You can make a RequestParam optional by adding the required flag false.
#RequestParam(value = "a", required=false)
For PathVariables i would try to use the Optional type but i have never done this before.
#PathVariable Optional<String> a for /path/{a}
I have below code to evaluate xpath expression.
String inputXml = "<?xml version=\"1.0\"?><!DOCTYPE document SYSTEM \"test.dtd\"><Request><Header><Version>1.0</Version></Header></Request>";
String xpath="/Request/Header/Version";
XPathFactory xpf = new net.sf.saxon.xpath.XPathFactoryImpl();
final InputSource is = new InputSource(new StringReader(inputXml));
String version = xpf.newXPath().evaluate(xpath, is);
xpf.newXPath().evaluate throws error as test.dtd couldn't be found. I want to disallow DTD completely. I have been reading about setting SAXParser feature "http://apache.org/xml/features/disallow-doctype-decl" but not sure how to apply in this case or is there any other way to disallow/ignore DTD's.
I'm not quite sure what you want to achieve. If you want this to fail because there is a DTD referenced, then you already seem to be achieving that.
However, if you want to set a property on the XML parser, there are two ways you could achieve it:
(a) Supply a SAXSource rather than an InputSource; initialize the XMLReader in the SAXSource to the XML parser you want to use, and use the XMLReader's setFeature interface to configure it before you pass it to the XPath engine.
(b) Set the Saxon configuration feature http://saxon.sf.net/feature/parserFeature?uri=http://apache.org/xml/features/disallow-doctype-decl (that's a single string with no spaces or newlines) to the value true. You can do this using
xpf.getConfiguration().setConfigurationProperty(featureName, true);
I am testing a controller using MockMvc. This is what the response looks like:
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {Content-Type=[text/xml]}
Content type = text/xml
Body = <?xml version="1.0" encoding="UTF-8" standalone="yes"?><ns2:diagnosisCode xmlns:ns2="http://schemas.mycompany.co.za/health" effectiveStartDate="2014-03-05T00:00:00+02:00" effectiveEndDate="2014-03-05T23:59:59.999+02:00" diagnosisId="1"><diagnosisCodeId><codingSchemaCode>irrelevant schema</codingSchemaCode><diagnosisCode>irrelevant code</diagnosisCode></diagnosisCodeId></ns2:diagnosisCode>
Forwarded URL = null
Redirected URL = null
Cookies = []
Pretty-printed version of the Body line:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:diagnosisCode xmlns:ns2="http://schemas.mycompany.co.za/health" effectiveStartDate="2014-03-05T00:00:00+02:00" effectiveEndDate="2014-03-05T23:59:59.999+02:00" diagnosisId="1">
<diagnosisCodeId>
<codingSchemaCode>irrelevant schema</codingSchemaCode>
<diagnosisCode>irrelevant code</diagnosisCode>
</diagnosisCodeId>
</ns2:diagnosisCode>
The call on MockMvc looks like
mockMvc.perform(
get("/diagnostic/diagnosisCodes/{schema}/{code}", IRRELEVANT_SCHEMA, IRRELEVANT_CODE).accept(MediaType.TEXT_XML))
.andDo(print())
.andExpect(content().contentType(MediaType.TEXT_XML))
.andExpect(status().isOk())
.andExpect(xpath("diagnosisCodeId/diagnosisCode").string(IRRELEVANT_CODE))
.andExpect(xpath("diagnosisCodeId/codingSchemaCode").string(IRRELEVANT_SCHEMA));
I am pretty sure I am misunderstanding how I'm supposed to use XPath here, but why is this assertion failing? What should my expectation look like?
java.lang.AssertionError: XPath diagnosisCode expected:<irrelevant code> but was:<>
I'm not totally sure what the XPath context is (or whether it is the document node), but I see two possible problems and guess both apply:
You try to match < diagnosisCodeId/> elements that are the root element. There are none, but they're children of <diagnosisCode>. Either include an axis step for the root node (probably better way) or use the descendant-or-self axis step // in front of the query.
/diagnosisCode/diagnosisCodeId/diagnosisCode
//diagnosisCodeId/diagnosisCode
The document uses namespaces (for the root element). In addition to the root element problem described above, either register that namespace (better solution, but I don't know how to do this in spring MVC) or ignore it using following workaround:
/*[local-name() = 'diagnosisCode']/diagnosisCodeId/diagnosisCode
Which first matches all child nodes, but then limits to the ones having the apropriate element name (ignoring namespaces).
By adding XPath 2.0 support (for example by including Saxon as library), you can also use the wildcard namespace matcher:
/*:diagnosisCode/diagnosisCodeId/diagnosisCode
If you register the namespace URI http://schemas.mycompany.co.za/health as ns2, the query would look like
/ns2:diagnosisCode/diagnosisCodeId/diagnosisCode
There is an overload for xpath that takes a Map<String, String> of namespaces:
Map<String, String> ns = Map.of("ns2", "http://schemas.mycompany.co.za/health");
mockMvc.perform(get("/diagnostic/diagnosisCodes/{schema}/{code}", IRRELEVANT_SCHEMA, IRRELEVANT_CODE)
.accept(MediaType.TEXT_XML))
.andExpect(xpath("ns2:diagnosisCodeId/diagnosisCode", ns).string(IRRELEVANT_CODE))
.andExpect(xpath("ns2:diagnosisCodeId/codingSchemaCode", ns).string(IRRELEVANT_SCHEMA));
Can I put /** wildcard in a middle of request mapping such as: "/some/resource/**/somthing"
In Spring 3 I can do this
#RequestMapping("/some/resource/**")
to map
/some/resource/A -> ControllerMethod1
/some/resource/A/B -> ControllerMethod1
/some/resource/A/B/C/D/E/F -> ControllerMethod1
for any number of paths parts
However this mapping is too greedy and will not allow me to map a sub URL #RequestMapping("/some/resource/**/somthing") to another controller such as
/some/resource/A/somthing -> ControllerMethod2
/some/resource/A/B/somthing -> ControllerMethod2
/some/resource/A/B/C/D/E/F/somthing -> ControllerMethod2
How can i do this?
I thinks it's not possible to use that ant style in url mapping as you require, because it will stop on the next path separator character '/'.
I would suggest you to try 16.3.2.2. URI Template Patterns with Regular Expressions in order to map just the last part of the request (haven't tried this approach yet).
Also you can match the rest of the request using PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, and apply some expression there. Check this post.
Otherwise you should use request parameters to match that condition 16.3.2.6. Request Parameters and Header Values.
You can narrow request matching through request parameter conditions such as "myParam", "!myParam", or "myParam=myValue". The first two test for request parameter presense/absence and the third for a specific parameter value. Here is an example with a request parameter value condition.
In this case you will map something like that using params
#RequestMapping(value = {"/some/resource/**"}, params="somthing")
or use the annotation request parameter with not required attribute in method signature:
public void test(#RequestParam(value = "somthing", required=false) String str) {