JUnit Test cases for Rest URL - rest

I am facing problem to write test cases for a rest url which calls another URL through Rest Template.
Please find my code below:-
#RestController
public class ParentController{
#Value("${child.url}")
private String childUrl;
#Autowired
private RestTemplateUtil restTemplateUtil;
#RequestMapping(value = "/parent",method = RequestMethod.POST)
public ResponseEntity<Object> callChildController(#RequestBody InputParam inputParam, HttpServletRequest request) {
return restTemplateUtil.templateService(restTemplateUtil.formURL(request, childUrl), HttpMethod.POST,null,inputParam, Object.class);
}}
}
#Service
public class RestTemplateUtil {
RestTemplate restTemplate = new RestTemplate();
public ResponseEntity<Object> templateService(String url, HttpMethod method, HttpHeaders headers, ...............){
logger.info("Rest template service called..");
response = restTemplate.exchange(url,method,entity,responseType);
return response;
}
public String formURL(HttpServletRequest request, String childUrl){
return "http://" + request.getServerName() + ":" + request.getServerPort() + childUrl;
}
}
JUnit Test case written:-
Mockito.when(restTemplateUtil.templateService(Mockito.anyString(),
Mockito.<HttpMethod> eq(HttpMethod.POST),
Mockito.<HttpHeaders> any(),
Mockito.<HttpEntity<?>> any(),
Mockito.<Class<Object>> any())).thenReturn(mockRespEntity);
this.mvc.perform(post("/parent")
.contentType(MediaType.APPLICATION_JSON)
.content(new ObjectMapper().writeValueAsString(requestObj)))
.andExpect(status().is2xxSuccessful());
I am a newbie to Mockito, so with my meagre knowledge have build the above test case.
Please advise and correct me if I am wrong.
On executing this, I am getting error:-
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:80/child": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect
The portno is wrong here.
Please help.
Thanks.

Related

HTTP request doesn't work with a paricular rest

I'm making an application filled with various rest services, so I create a one-for-all HTTP class in order to allow a client application to keep asking information, via rest, to a server application
public HttpURLConnection HTTPSENDJSON(String urlAPI,String out,String requestmethod) throws IOException {
URL url = new URL(urlAPI);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestMethod(requestmethod);
conn.setDoOutput(true);
conn.setDoInput(true);
OutputStream os = conn.getOutputStream();
System.out.println(out);
os.write(out.getBytes());
os.flush();
os.close();
return conn;
urlAPI is the desired URL, a string is the JSON string (I'm using GSON) and the requestmethod is a string in order to switch from PUT\POST\GET\PATCH.
So, as I wrote, it's all ok if I need to retrieve information from DB\insert a new record
ATM my Client application makes a call to the server who calls an EJB in order to CRUD the information.
this is the Client method who call the upper method (the HTTPSENDJSON )
public String modifica() throws IOException {
Universal_HTTPREQUEST httprequest = new Universal_HTTPREQUEST();
String url= "http://localhost:8080/ModuloWebClientNuovo/rest/clientela/modifica/account/"+ac.getId()+"";
Gson g = new Gson();
String out=g.toJson(ac, Account.class);
httprequest.HTTPSENDJSON(url, out,"PUT");
and this is the working (at least with POSTMAN) services
#PUT
#Path("modifica/account/{id}")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response modificaaccount(#PathParam("id") int id,Account a) {
System.out.println("i'm inside the api and i wrote: "+ a.toString());
ac.updateAccount(a);
return Response.status(200).entity(a).build() ;
}
The Client doesn't even make the call to the server, BUT the only with this specific rest, other works fine.
update account EJB is:
#Stateless
public class AccountEJB implements IAccountCrud {
#EJB
Iconnessioni x;
#Override
public void updateAccount(Account account) {
EntityManager entityManager=x.apriconnessione();
entityManager.merge(account);
x.chiudiconnessione(entityManager);
}
}
Fixed whit a new from scratch wildfly

Mocking an autowired field using mockito gives null response in rest call

I am using spring boot and mockito. I have autowired one class i.e, BDSRequest and in Junit Test class, i have used #Spy and #InjectMocks annotations. but while calling rest services in Junits, i am getting response (bdsCustomerHoldings) as null and assertion is failing. How to test this rest call with out mocking rest template like mockito.when(restTemplate.postForObject(Constants.BDS_REST_URL, bdsRequest,
BDSCustomerHoldings.class) ?
class BDSRestCall
{
#Autowired
BDSRequest bdsRequest;
public BDSCustomerHoldings getBDSCustomerInfo(String channelId, String customerId, String cinSuffix,
String countryCode) {
logger.info("prepareRequestForBDS");
Header header = new Header();
header.setMsgId(RandomStringUtils.randomAlphanumeric(20));
header.setChannelId(channelId);
header.setCountryCode(countryCode);
header.setRecordTimeStamp(DateTimeFormatter.ofPattern(Constants.DATE_FORMATTER).format(LocalDateTime.now()));
TxnRequest txnRequest = new TxnRequest();
txnRequest.setIdDoc(customerId);
txnRequest.setIdDocSuffix(cinSuffix);
txnRequest.setIdDoctype("");
txnRequest.setInsurerCode("");
bdsRequest.setHeader(header);
bdsRequest.setTxnRequest(txnRequest);
logger.info("BDS request " + bdsRequest);
BDSCustomerHoldings bdsResponse = restTemplate.postForObject(Constants.BDS_REST_URL, bdsRequest,
BDSCustomerHoldings.class);
logger.info("BDS Response : " + bdsResponse);
return bdsResponse;
}
}
Junit:
#RunWith(MockitoJUnitRunner.class)
class BDSRestCallTest
{
#InjectMocks
private BDSRestCall bdsRestCall;
#Mock
private RestTemplate restTemplate;
#Spy
private BDSRequest bdsRequest;
#Test
public void getBDSCustomerInfoExceptionTest() {
BDSCustomerHoldings bdsCustomerHoldings = bdsRestCall.getBDSCustomerInfo("SG", "S9718016D",
"00", "SG");
System.out.println("response is " + bdsCustomerHoldings);
assertNotNull("response is not null", bdsCustomerHoldings);
}
}
As we are using #RunWith(MockitoJUnitRunner.class), then we should use mocking the response of restTemplate like below
Mockito.when(restTemplate.postForObject(Mockito.anyString(), bdsRequest, BDSCustomerInsuranceHoldings.class)).thenReturn(sampleBDSCustomerInsuranceHoldings());
Then it will give mock response.

Why the basic authentification gives always error 403 with restTemplate?

I tried multiple ways to call a get url via RestTemplate in spring boot project to get a json, but every time i got the following 403 error:
<200,{"request":{"mbean":"org.apache.activemq.artemis:address=%22my.queue.demo%22,broker=%22141.110.112.13%22,component=addresses,queue=%22my.queue.demo%22,routing-type=%22anycast%22,subcomponent=queues","attribute":"MessageCount","type":"read"},"error_type":"java.lang.Exception","error":"java.lang.Exception
: Reading attribute MessageCount is forbidden for MBean
org.apache.activemq.artemis:address=%22my.queue.demo%22,broker=%22141.110.112.13%22,component=addresses,queue=%22my.queue.demo%22,routing-type=%22anycast%22,subcomponent=queues","status":403},[Date:"Wed,
12 Jun 2019 12:56:22 GMT", Cache-Control:"no-cache",
Pragma:"no-cache", Access-Control-Allow-Origin:"*",
X-Frame-Options:"SAMEORIGIN", X-XSS-Protection:"1",
Content-Type:"text/plain;charset=utf-8", Expires:"Wed, 12 Jun 2019
11:56:22 GMT", Transfer-Encoding:"chunked"]>
This is the url that i try to call:
http://10.185.148.153:1495/console/jolokia/read/org.apache.activemq.artemis:broker=%22141.110.112.13%22,component=addresses,address=%22my.queue.demo%22,subcomponent=queues,routing-type=%22anycast%22,queue=%22my.queue.demo%22/MessageCount
When i use Postman with basic authentification (user= test, pass =test) it works find but not with Resttemplate.
Here is my config class:
#SpringBootApplication
public class StartWebApplication {
public static void main(String[] args) {
SpringApplication.run(StartWebApplication.class, args);
}
}
#Configuration
class Appconfig{
#Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
My confroller:
...
#Autowired
private RestTemplate restTemplate;
....
restTemplate.exchange(url, HttpMethod.GET, createHeaders("test", "test"), String.class)
....
HttpEntity createHeaders(String username, String password) {
byte[] token = Base64.getEncoder().encode(
(username + ":" + password).getBytes());
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + new String(token));
HttpEntity<String> request = new HttpEntity<>(headers);
return request;
}
}
With RestTemplate, you can avoid some of the Base64 boilerplate with:
#Bean
RestTemplate rest() {
RestTemplate rest = new RestTemplate();
rest.getInterceptors().add(new BasicAuthenticationInterceptor("test", "test"));
return rest;
}
Then you can simply do:
rest.getForObject(url, String.class);
Not sure if the problem is something in your Base64-ing of the username and password, but doing this would eliminate that as a possibility.
Can you try:
String auth = username + ":" + password;
byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(Charset.forName("US-ASCII")));
headers.add("Authorization", "Basic " + new String(encodedAuth));
You can try this solution:
1/ Your username/password is incorrect:
Configure J4pClient client using:
J4pClient
.url(JOLOKIA_URL)
.user(USERNAME)
.password(PASSWORD)
.authenticator(new BasicAuthenticator().preemptive())
.build();
pom.xml sample:
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-client-java</artifactId>
<version>${jolokia-client-java.version}</version>
</dependency>
2/ JMS Broker does not allow you to access given attribute or CORS issues:
See here: https://jolokia.org/reference/html/security.html how to configure jolokia. E.g. configure etc/jolokia-access.xml for AcviveMQ Artemis.

Generating random session id whenever user uses login() in web services

Am new to web services. Am trying to generate unique session id for every login that a user does, in web services.
What I thought of doing is,
Write a java file which has the login and logout method.
Generate WSDL file for it.
Then generate web service client(using Eclipse IDE), with the WSDl file which I generate.
Use the generated package(client stub) and call the methods.
Please let me know if there are any flaws in my way of implementation.
1. Java file with the needed methods
public String login(String userID, String password) {
if (userID.equalsIgnoreCase("sadmin")
&& password.equalsIgnoreCase("sadmin")) {
System.out.println("Valid user");
sid = generateUUID(userID);
} else {
System.out.println("Auth failed");
}
return sid;
}
private String generateUUID(String userID) {
UUID uuID = UUID.randomUUID();
sid = uuID.toString();
userSessionHashMap = new HashMap<String, String>();
userSessionHashMap.put(userID, sid);
return sid;
}
public void logout(String userID) {
Set<String> userIDSet = userSessionHashMap.keySet();
Iterator<String> iterator = userIDSet.iterator();
if (iterator.equals(userID)) {
userSessionHashMap.remove(userID);
}
}
2. Generated WSDL file
Developed the web service client from the wsdl.
4. Using the developed client stub.
public static void main(String[] args) throws Exception {
ClientWebServiceLogin objClientWebServiceLogin = new ClientWebServiceLogin();
objClientWebServiceLogin.invokeLogin();
}
public void invokeLogin() throws Exception {
String endpoint = "http://schemas.xmlsoap.org/wsdl/";
String username = "sadmin";
String password = "sadmin";
String targetNamespace = "http://WebServiceLogin";
try {
WebServiceLoginLocator objWebServiceLoginLocator = new WebServiceLoginLocator();
java.net.URL url = new java.net.URL(endpoint);
Iterator ports = objWebServiceLoginLocator.getPorts();
while (ports.hasNext())
System.out.println("ports Iterator size-->" + ports.next());
WebServiceLoginPortType objWebServiceLoginPortType = objWebServiceLoginLocator
.getWebServiceLoginHttpSoap11Endpoint();
String sid = objWebServiceLoginPortType.login(username, password);
System.out.println("sid--->" + sid);
} catch (Exception exception) {
System.out.println("AxisFault at creating objWebServiceLoginStub"
+ exception);
exception.printStackTrace();
}
}
On running the this file, I get the following error.
AxisFault
faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server.userException
faultSubcode:
faultString: java.net.ConnectException: Connection refused: connect
faultActor:
faultNode:
faultDetail:
{http://xml.apache.org/axis/}stackTrace:java.net.ConnectException: Connection refused: connect
Can anyone suggest an alternate way of handling this task ? And what could probably be the reason for this error.
Web services are supposed to be stateless, so having "login" and "logout" web service methods doesn't make much sense.
If you want to secure web services calls unfortunately you have to code security into every call. In your case, this means passing the userId and password to every method.
Or consider adding a custom handler for security. Read more about handlers here.

How to handle an invalid content type in Rest Template?

I am querying a REST API, for negative cases in response I am getting a 200 code and some weird Content-type in headers. Because of this I am unable to store the response, as it throws an exception while parsing.
Below image shows the headers from the response:
ResponseErrorHandler:
#Component
public class AutomationResponseErrorHandler implements ResponseErrorHandler{
private static final Logger logger = LoggerFactory.getLogger(AutomationResponseErrorHandler.class);
#Override
public boolean hasError(ClientHttpResponse response) throws IOException {
// TODO Auto-generated method stub
return response.getStatusCode() != HttpStatus.OK;
}
#Override
public void handleError(ClientHttpResponse response) throws IOException {
logger.error("Response Error: {} {} {}", response.getStatusCode(), response.getStatusText(), response.getBody());
}
}
Custom RestTemplate:
#Component
public class CustomRestTemplate {
#Autowired
AutomationResponseErrorHandler responseErrorHandler;
public RestTemplate getRestTemplate(boolean isHttpsRequired)
throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
// if https is not required,
if (!isHttpsRequired) {
return new RestTemplate();
}
// else below code adds key ignoring logic for https calls
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy)
.build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);
restTemplate.setErrorHandler(responseErrorHandler);
return restTemplate;
}
}
Below is the code for saving response:
ResponseEntity<String> response = restTemplate.getForEntity(outBound, String.class);
Below is the Exception occured:
at org.springframework.http.MediaType.parseMediaType(MediaType.java:534)
at org.springframework.http.HttpHeaders.getContentType(HttpHeaders.java:869)
at org.springframework.web.client.HttpMessageConverterExtractor.getContentType(HttpMessageConverterExtractor.java:124)
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:88)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:991)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:974)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:725)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:680)
at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:359)
at com.att.aotsm.msnautomationscheduler.TicketCloseAutomation.queryTicketCloseAPI(TicketCloseAutomation.java:54)
at com.att.aotsm.msnautomationscheduler.AutomationInvokeWebService.queryTicketCloseAPI(AutomationInvokeWebService.java:71)
at com.att.aotsm.msnautomationscheduler.AutomationThreadProcess.run(AutomationThreadProcess.java:138)
at java.lang.Thread.run(Unknown Source)
Caused by: org.springframework.util.InvalidMimeTypeException: Invalid mime type "`colnames<-`(`*tmp*`, value = c("MSN/Port", "Count"))": does not contain '/'
at org.springframework.util.MimeTypeUtils.parseMimeType(MimeTypeUtils.java:194)
at org.springframework.http.MediaType.parseMediaType(MediaType.java:531)
... 12 more
I want the to save the response body, no matter whatever the content-type is.