JAX-RS Response.getEntity() always null - jax-rs

I need help with Arquillian test.
Add code example of situation.
This code is working ok in real environment. Only in test case made with arquillian the result is not expected
The code:
#Stateless
public class CustomerResourceImpl implements CustomerResource{
#Override
public Response findOne(String id) {
String res = "Un cliente";
return Response.ok(res).build();
}
}
#Path("customer")
#Produces(MediaType.APPLICATION_JSON)
public interface CustomerResource {
#GET
#Path("/findOne")
public javax.ws.rs.core.Response findOne(#QueryParam("id") String id);
}
And this test case
#RunWith(Arquillian.class)
public class CustomerResourceTest {
#Deployment (testable = false)
public static Archive createTestArchive() {
return ShrinkWrap
..... (mas)
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
}
#ArquillianResource
private URL deploymentURL;
#Test
#RunAsClient
public void findOne(#ArquillianResteasyResource CustomerResource resource) throws Exception {
final Response response = resource.findOne("1");
System.out.println(response.getEntity()); // IS NULL ??
System.out.println(response.getStatus()); // 200 OK
assertNotNull(response);
}
}
The problem is that response.getEntity() is always NULL . Why? The status response OK = 200 , it is OK. This service run ok in jboss 7.2 with Java 8.
Thanks!

The reason is #Deployment (testable = false)
#Deployment says:
testable = Defines if this deployment should be wrapped up based on the protocol so the testcase can be executed incontainer.
So false means it will not be deployed in the container, and therefore will be null when your tests run inside the container.
I recommend using #Deployment with not parameters passed in rather than setting testable = true
I just solved this today after a days of fiddling. I think I pasted the #Deployment (testable = false) code from examples on the internet that I didn't understand hoping to get something working.

Related

In TechTalk SpecFlow, how do I abandon a Scenario?

My scenario reads a file with hundreds of lines. Each line calls an API Service, but the service may not be running. If I get a non-200 response (available inside the 'Then' method), I want to abandon the Scenario & save time.
How can I tell TechTalk SpecFlow to not carry on with the other tests?
You can use a concept like this .
public static FeatureContext _featureContext;
public binding( FeatureContext featureContext)
{
_featureContext = featureContext;
}
[Given(#"user login")]
public void login(){
// do test
bool testPassed = //set based on test. true or false
binding._featureContext.Current["testPass"] = testPassed;
}
Then in BeforeScenario()
[BeforeScenario(Order = 1)]
public void BeforeScenario()
{
Assert.IsTrue(FeatureContext.Current["testPass"];);
}

Testng - Skip dependent tests for only failed data sets

I am attempting to modify my dependent tests so they are ran in a specific way and have yet find a way possible. For instance, say I have the following two tests and the defined data provider:
#Dataprovider(name = "apiResponses")
Public void queryApi(){
return getApiResponses().entrySet().stream().map(response -> new Object[]{response.getKey(), response.getValue()}).toArray(Object[][]::new);
}
#Test(dataprovider = "apiResponses")
Public void validateApiResponse(Object apiRequest, Object apiResponse){
if(apiResponse.statusCode != 200){
Assert.fail("Api Response must be that of a 200 to continue testing");
}
}
#Test(dataprovider = "apiResponses", dependsOnMethod="validateApiResponse")
Public void validateResponseContent(Object apiRequest, Object apiResponse){
//The following method contains the necessary assertions for validating api repsonse content
validateApiResponseData(apiResponse);
}
Say I have 100 api requests I want to validate, with the above, if a single one of those 100 requests were to return a status code of anything other than 200, then validateResponseContent would be skipped for all 100. What I'm attempting to achieve is that the dependent tests would be skipped for only the api responses that were to return without a status code of 200 and for all tests to be ran for responses that returned WITH a status code of 200.
You should be using a TestNG Factory which creates instances with both the apiRequest and apiResponse in it for each instance. Now each instance would basically first run an assertion on the status code before it moves on to validating the actual api response.
Here's a sample that shows how this would look like:
public class TestClassSample {
private Object apiRequest, apiResponse;
#Factory(dataProvider = "apiResponses")
public TestClassSample(Object apiRequest, Object apiResponse) {
this.apiRequest = apiRequest;
this.apiResponse = apiResponse;
}
#Test
public void validateApiResponse() {
Assert.assertEquals(apiResponse.statusCode, 200, "Api Response must be that of a 200 to continue testing");
}
#Test(dependsOnMethods = "validateApiResponse")
public void validateResponseContent() {
//The following method contains the necessary assertions for validating api repsonse content
validateApiResponseData(apiResponse);
}
#DataProvider(name = "apiResponses")
public static java.lang.Object[][] queryApi() {
return getApiResponses().entrySet()
.stream().map(
response -> new java.lang.Object[]{
response.getKey(), response.getValue()
})
.toArray(Object[][]::new);
}
}
Would'nt adding a if/else block solve this?
#Test(dataprovider = "apiResponses")
Public void validateApiResponse(Object apiRequest, Object apiResponse){
if(apiResponse.statusCode != 200){
Assert.fail("Api Response must be that of a 200 to continue testing");
} else {
validateApiResponseData(apiResponse);
}
}

How JAXB/Jersey unmarshall Boolean values?

I have an issue with some RESTful services that takes a transfer object in parameter (basically an XML object that will be unmarshalled to a POJO).
#XmlRootElement(name = "myPojo")
public class MyPojo {
#XmlElement(name = "myField")
private Boolean myBoolean;
public void setMyBoolean(Boolean bool) {
myBoolean = bool;
}
public Boolean getMyBoolean() {
return myBoolean;
}
}
And the service is something like that:
public class MyRestService {
#PUT
#Path("somewhere")
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response update(MyPojo pojo) {
System.out.println("Boolean value: " + pojo.getMyBoolean();
}
}
If I post this XML fragment:
<myPojo>
<myField>false</myField>
</myPojo>
I got:
Boolean value: false
And if I post this XML fragment:
<myPojo>
<myField>FALSE</myField>
</myPojo>
I got:
Boolean value: null
I run that code under Glassfish 4 with Jersey 1.9.1 and JAXB 2.2.7. In addition, under Glassfish 2, I got a different behavior where both uppercase and lowercase are unmarshalled as expected.
So, I am really curious to know what is happening and why the marshalling of boolean is different.
Thanks in advance
I run into the same problem today where JAXB returns null when parsing "FaLsE" or "True" on a Boolean field. Unfortunately, upgrading to 2.2.7 or above (2.2.11 as of today) didn't help me. When I dig deeper into the source code, it seems that the parsing logic happens inside DatatypeConverterImpl.java. And there is no configuration that can alter its behavior on uppercase.
Link to JAXB DatatypeConverterImpl.java
The solution that I found (and works), is to define a new BooleanAdapter and asks JAXB to use that instead. In the adapter, you can define whatever conversion logic that fits your application.
Custom BooleanAdapter.java
public class BooleanAdapter extends XmlAdapter<String, Boolean> {
#Override
public Boolean unmarshal(String v) throws Exception {
if (StringUtils.isBlank(v))
return null;
return Boolean.valueOf(v);
}
#Override
public String marshal(Boolean v) throws Exception {
if (v == null)
return null;
return v.toString();
}
}
Your model object
#XmlElement(name = "myField")
#XmlJavaTypeAdapter(BooleanAdapter.class)
public Boolean getMyBoolean() {
return myBoolean;
}
After several investigations, we figured out that the version 2.2 of JAXB we are using seems to contain a bug that serialize the boolean values not as expected. I mean that for example: FaLsE will be converted to null value.
Upgrading to the version 2.2.7 has fixed our issue.

How to implement a Restlet JAX-RS handler which is a thin proxy to a RESTful API, possibly implemented in the same java process?

We have two RESTful APIs - one is internal and another one is public, the two being implemented by different jars. The public API sort of wraps the internal one, performing the following steps:
Do some work
Call internal API
Do some work
Return the response to the user
It may happen (though not necessarily) that the two jars run in the same Java process.
We are using Restlet with the JAX-RS extension.
Here is an example of a simple public API implementation, which just forwards to the internal API:
#PUT
#Path("abc")
public MyResult method1(#Context UriInfo uriInfo, InputStream body) throws Exception {
String url = uriInfo.getAbsolutePath().toString().replace("/api/", "/internalapi/");
RestletClientResponse<MyResult> reply = WebClient.put(url, body, MyResult.class);
RestletUtils.addResponseHeaders(reply.responseHeaders);
return reply.returnObject;
}
Where WebClient.put is:
public class WebClient {
public static <T> RestletClientResponse<T> put(String url, Object body, Class<T> returnType) throws Exception {
Response restletResponse = Response.getCurrent();
ClientResource resource = new ClientResource(url);
Representation reply = null;
try {
Client timeoutClient = new Client(Protocol.HTTP);
timeoutClient.setConnectTimeout(30000);
resource.setNext(timeoutClient);
reply = resource.put(body, MediaType.APPLICATION_JSON);
T result = new JacksonConverter().toObject(new JacksonRepresentation<T>(reply, returnType), returnType, resource);
Status status = resource.getStatus();
return new RestletClientResponse<T>(result, (Form)resource.getResponseAttributes().get(HeaderConstants.ATTRIBUTE_HEADERS), status);
} finally {
if (reply != null) {
reply.release();
}
resource.release();
Response.setCurrent(restletResponse);
}
}
}
and RestletClientResponse<T> is:
public class RestletClientResponse<T> {
public T returnObject = null;
public Form responseHeaders = null;
public Status status = null;
public RestletClientResponse(T returnObject, Form responseHeaders, Status status) {
this.returnObject = returnObject;
this.responseHeaders = responseHeaders;
this.status = status;
}
}
and RestletUtils.addResponseHeaders is:
public class RestletUtils {
public static void addResponseHeader(String key, Object value) {
Form responseHeaders = (Form)org.restlet.Response.getCurrent().getAttributes().get(HeaderConstants.ATTRIBUTE_HEADERS);
if (responseHeaders == null) {
responseHeaders = new Form();
org.restlet.Response.getCurrent().getAttributes().put(HeaderConstants.ATTRIBUTE_HEADERS, responseHeaders);
}
responseHeaders.add(key, value.toString());
}
public static void addResponseHeaders(Form responseHeaders) {
for (String headerKey : responseHeaders.getNames()) {
RestletUtils.addResponseHeader(headerKey, responseHeaders.getValues(headerKey));
}
}
}
The problem is that if the two jars run in the same Java process, then an exception thrown from the internal API is not routed to the JAX-RS exception mapper of the internal API - the exception propagates up to the public API and is translated to the Internal Server Error (500).
Which means I am doing it wrong. So, my question is how do I invoke the internal RESTful API from within the public API implementation given the constraint that both the client and the server may run in the same Java process.
Surely, there are other problems, but I have a feeling that fixing the one I have just described is going to fix others as well.
The problem has nothing to do with the fact that both internal and public JARs are in the same JVM. They are perfectly separated by WebResource.put() method, which creates a new HTTP session. So, an exception in the internal API doesn't propagate to the public API.
The internal server error in the public API is caused by the post-processing mechanism, which interprets the output of the internal API and crashes for some reason. Don't blame the internal API, it is perfectly isolated and can't cause any troubles (even though it's in the same JVM).

TestNG Test Case failing with JMockit "Invalid context for the recording of expectations"

The following TestNG (6.3) test case generates the error "Invalid context for the recording of expectations"
#Listeners({ Initializer.class })
public final class ClassUnderTestTest {
private ClassUnderTest cut;
#SuppressWarnings("unused")
#BeforeMethod
private void initialise() {
cut = new ClassUnderTest();
}
#Test
public void doSomething() {
new Expectations() {
MockedClass tmc;
{
tmc.doMethod("Hello"); result = "Hello";
}
};
String result = cut.doSomething();
assertEquals(result, "Hello");
}
}
The class under test is below.
public class ClassUnderTest {
MockedClass service = new MockedClass();
MockedInterface ifce = new MockedInterfaceImpl();
public String doSomething() {
return (String) service.doMethod("Hello");
}
public String doSomethingElse() {
return (String) ifce.testMethod("Hello again");
}
}
I am making the assumption that because I am using the #Listeners annotation that I do not require the javaagent command line argument. This assumption may be wrong....
Can anyone point out what I have missed?
The JMockit-TestNG Initializer must run once for the whole test run, so using #Listeners on individual test classes won't work.
Instead, simply upgrade to JMockit 0.999.11, which works transparently with TestNG 6.2+, without any need to specify a listener or the -javaagent parameter (unless running on JDK 1.5).