I want to test http request/response. So I use WireMock.
I want to stub response for specific request:
Here code:
public class WireMockPersons {
#Rule
public WireMockRule wireMockRule = new WireMockRule(8089);
#Test
public void exactUrlOnly() {
stubFor(get(urlEqualTo("/some/thing"))
.willReturn(aResponse()
.withHeader("Content-Type", "text/plain")
.withBody("Hello world!")));
assertThat(testClient.get("/some/thing").statusCode(), is(200));
assertThat(testClient.get("/some/thing/else").statusCode(), is(404));
}
Code is not compile because no object testClient. How I can get testClient object?
testClient is your client library for the API you are mocking.
Looks like you have copied directly from the examples which are indicative only.
Replace testClient with the HTTP library of your choosing, for example HttpClient.
String url = "http://localhost:8089/some/thing";
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
HttpGet get = new HttpGet(url);
HttpEntity entity = client.execute(get).getEntity();
return EntityUtils.toString(entity, "UTF-8");
} catch (IOException e) {
throw new RuntimeException("Unable to call " + url, e);
}
Related
I'm using Citrus static response adapter to mock services, and I need to change values in its payload for every test case. Ideally I think about usage of dictionaries for each test case. There is sample of my current scenario:
#Autowired
#Qualifier("checkRegistrationEndpointAdapter")
public StaticResponseEndpointAdapter checkRegistrationEndpointAdapter;
protected void setAdapterResponse(StaticResponseEndpointAdapter adapter, String filenamepath){
URL url = this.getClass().getResource(filenamepath);
String payload = null;
try {
payload = Resources.toString(url, Charsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
}
adapter.setMessagePayload(payload);
}
#CitrusTest
public void TestCase02() throws IOException {
http()
.client(CLIENT)
.post()
.payload(new ClassPathResource("templates/thisStartRequestMsg.xml", getClass()))
.dictionary("TC02");
http()
.client(CLIENT)
.response()
.messageType("xml")
.payload(new ClassPathResource("templates/thisStartResponseMsg.xml", getClass()));
action(new AbstractTestAction() {
#Override
public void doExecute(TestContext testContext) {
setAdapterResponse(checkRegistrationEndpointAdapter, "templates/check-registration-v1CheckRegistrationResponseMsg.xml");
}
});
http()
.client(CLIENT)
.response()
.messageType("xml")
.payload(new ClassPathResource("templates/check-registration-v1CheckRegistrationRequestMsg.xml", getClass()))
.dictionary("TC02");
}
How can I apply dictionary to the payload set in my setAdapterResponse method?
Note: this question relates to Can I use Citrus variable in Citrus static response adapter payload?
Static response adapter has currently no support for data dictionaries. I wonder why you put so much effort into static response adapters? Why not using the full Citrus http server power with receiving the request and providing a response inside the test case?
I want to pass an JSONObject from restful service to a restful client . Here is pice of my service code :
#GET
#Path("/getJson")
#Produces(MediaType.APPLICATION_JSON)
public JSONObject getJson() {
try {
JSONObject json=new JSONObject();
json.put("PoprocessingCode", "123456789");
json.put("TransactionAmount", "0000000");
System.out.println(json);
return json;
} catch (Exception e) {
System.err.println(e.getMessage());
return null;
}
}
and here is pice of my restful client :
Client c = Client.create();
WebResource resource = c.resource("http://localhost:8080/TestJsonService/jaxrs/JsonService/getJson");
JSONObject json=new JSONObject();
json=resource.accept(MediaType.APPLICATION_JSON_TYPE).get(JSONObject.class);
try {
System.out.println("json.getString = "+json.getString("PoprocessingCode"));
} catch (JSONException e1) {
e1.printStackTrace();
}
when I ran it , I get this error :
org.json.JSONException: JSONObject["PoprocessingCode"] not found.
at org.json.JSONObject.get(JSONObject.java:459)
at org.json.JSONObject.getString(JSONObject.java:640)
at JsonClient.main(JsonClient.java:30)
I tested my service by Test with "REST Web Service Explorer" in myeclipse and recognized get method in service T returned just this
{}
and there isn't anything in it and it is empty , I don't know why?!
please guide me in order to solve it.
thanks...
Please pass the JsonObject in this form, this will work :
#Path("Excel")
#POST
#GET
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public String ExportToExcel(String jsonString)
And post this using REST Console.
In case of :
JsonObject then use this --->
#Path("/rename")
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Event renameEvent(Event newEvent)
And the object that you pass from the REST CONSOLE should be of following pattern :
{"measures":null,"eventScenarioId":2016,"timeId":20378,"promoPrice":1.979734,"oiAllowancePerunit":0.0,"productId":7158,"scanAllowancePerUnit":0.0,"eventProductStrategy":[{"name":"FND","tsId":4,"tsACV":10.0,"eventProductScenarioId":5069,"id":3},{"name":"TPR","tsId":1,"tsACV":0.0,"eventProductScenarioId":5069,"id":4},{"name":"DISPLAY","tsId":3,"tsACV":2.0,"eventProductScenarioId":5069,"id":2},{"name":"FEATURE","tsId":2,"tsACV":9.0,"eventProductScenarioId":5069,"id":1}],"addEstimatedIncrementalUnits":0.0,"shippedBaseUnits":4365.000000000001,"edShelfPrice":1.979734,"eventFixedCost":0.0,"shippedUnitPct":100.0,"edlpPricePerUnit":0.0,"manuFixedCost":0.0,"customerId":null,"id":5069}
There is a good example for sharing HttpSession between Websocket and Rest service. (Spring DispatchServlet cannot find resource within Jetty) But it doesn't work for me. I'm not sure is there any thing I'm missing?
I'm using Jetty as websocket server and also I created a WebApp as well which injected by SpringConfig.
private void init() throws Exception
{
Server server = new Server();
// Create SSL Connector
ServerConnector serverConnector = getSSLConnector(server);
// Bundle to server
server.setConnectors(new Connector[] { serverConnector });
// Create request handler collection
HandlerCollection handlers = new HandlerCollection();
// Add WebSocket handler
final ServletContextHandler servletContextHandler = getWebSocketContextHandler();
handlers.addHandler(servletContextHandler);
// Add Servlet handler
handlers.addHandler(getWebAppServletContextHandler());
server.setHandler(handlers);
// Initial WebSocket
WebSocketServerContainerInitializer.configureContext(servletContextHandler);
// Start Jetty
server.start();
server.join();
}
Both WebSocket and Rest are working under same port perfectly, of course, with different context paths.
Now, I created a Rest service:
#RequestMapping(value = "/login", method = RequestMethod.POST)
#Consumes({ MediaType.APPLICATION_JSON_VALUE })
#Produces({ MediaType.APPLICATION_JSON_VALUE })
public #ResponseBody Message login(#RequestBody Credential credential, #Context HttpServletRequest servlerRequest)
{
...
HttpSession session = servlerRequest.getSession(true);
session.setAttribute("userName", credential.getUserName());
...
Message message = new Message();
...
return message;
}
In this service I created a HttpSession and stored something in. As I said, it works, and so does the session.
Rest client:
public void login() throws KeyManagementException, NoSuchAlgorithmException
{
final String loginServiceUri = HTTP_SERVICE_BASE_URI + "/login";
ClientConfig clientConfig = new DefaultClientConfig();
...
Client client = Client.create(clientConfig);
WebResource webResource = client.resource(loginServiceUri);
ClientResponse response = webResource
.type("application/json")
.post(ClientResponse.class, new Credential("user","pass"));
if (response.getStatus() != 200) {
throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
}
List<NewCookie>cookies = response.getCookies();
ClientEndpointConfigurator.setCookies(cookies); <== Store cookies as well as session to ClientEndpointConfigrator class
Message message = response.getEntity(Message.class);
...
}
ClientEndpointConfigrator class has a static list for all cookies which like this:
public class ClientEndpointConfigurator extends ClientEndpointConfig.Configurator {
private static List<NewCookie> cookies = null;
public static void setCookies(List<NewCookie> cookies) {
ClientEndpointConfigurator.cookies = cookies;
}
...
#Override
public void beforeRequest(Map<String, List<String>> headers) {
...
if(null != cookies)
{
List<String> cookieList = new ArrayList<String>();
for(NewCookie cookie: cookies)
{
cookieList.add(cookie.toString());
}
headers.put("Cookie", cookieList);
}
...
}
}
beforeRequest() method will put all cookies to request header. If you inspect the cookieList, you will see:
[JSESSIONID=tvum36z6j2bc1p9uf2gumxguh;Version=1;Path=/rs;Secure]
Things looks prefect.
Finally, create a server end ServerEndpointConfigurator class, and override the modifyHandshake() method to retrieve the session and cookies
public class SpringServerEndpointConfigurator extends ServerEndpointConfig.Configurator {
#Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
super.modifyHandshake(sec, request, response);
httpSession = (HttpSession)request.getHttpSession(); <== **It returns null here!**
...
}
}
}
I can't get my HttpSession back! and if you print headers out, you will see the cookie has been changed:
Cookie: JSESSIONID="tvum36z6j2bc1p9uf2gumxguh";$Path="/rs"
Any one knows what's the reason?
All right, I figured it out, it's because I put WebSocket and Rest to different context handler. Jetty keeps handlers isolate to each other. To share session information, you have to put them together.
But if someone does want to separate them, it is still possible done by sharing SessionManager or SessionHandler. There are many ways to achieve this, you can inject SessionHandler to each ServletContext or just define it as a static variable and put it on somewhere every one can reach, each way works.
I have a wildcard cert for *.mydomain.com (the names have been changed to protect the innocent...that is NOT the real domain :) )
When using a correctly implemented Java HttpClient 4 (the issue is not seen in FF), Service calls made via HTTPS to api.mydomain.com are successful where as identical service calls made to non-production subdomains of mydomain.com (developer.mydomain.com, api-beta.mydomain.com, api-uat.mydomain.com) generate this Exception with the Test harness code below:
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at com.sun.net.ssl.internal.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:352)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:397)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:148)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:149)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:121)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:573)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:425)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732)
at com.mydomain.httpclientexample.HttpClientTestv2.main(HttpClientTestv2.java:54)
While the SLL cert on developer.mydomain.com, api-beta.mydomain.com & api-uat.mydomain.com appears to be the same WC cert as api.mydomain.com, the exception is not seen on api.mydomain.com but it is on the other sub-domains. The code works on api-na.mydomain.com and should work on the non-production subdomains.
Any ideas?
Client code: As you can see, I can easily change the ADDRESS_VALIDATION_SERVICE_URI I want to call. The api.mydomain.com one works without the SSLPeerUnverifiedException; the other three URIs throw the exception...
package com.mydomain.httpclientexample;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
public class HttpClientTestv2 {
//public final static String ADDRESS_VALIDATION_SERVICE_URI = "https://developer.mydomain.com/v1.0/stores/MYSTORE/address/validate.xml";
public final static String ADDRESS_VALIDATION_SERVICE_URI = "https://api-beta.mydomain.com/v1.0/stores/MYSTORE/address/validate.xml";
//public final static String ADDRESS_VALIDATION_SERVICE_URI = "https://api-uat.mydomain.com/v1.0/stores/MYSTORE/address/validate.xml";
//public final static String ADDRESS_VALIDATION_SERVICE_URI = "https://api.mydomain.com/v1.0/stores/MYSTORE/address/validate.xml";
public final static String APIKEY_ATTRIBUTE_NAME = "apikey";
public final static String APIKEY_ATTRIBUTE_VALUE = "2c90bc83e821364ffa557486c3e2a44e";
/**
* #param args
*/
public static void main(String[] args) {
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(ADDRESS_VALIDATION_SERVICE_URI);
System.out.println("executing request" + httpPost.getRequestLine());
//set a request header
httpPost.setHeader(APIKEY_ATTRIBUTE_NAME , APIKEY_ATTRIBUTE_VALUE);
//add the xml body
StringEntity postBody = null;
try {
postBody = new StringEntity(getXMLDoc(),"UTF-8");
} catch (UnsupportedEncodingException uee) {
System.out.println("----------------------------------------");
System.out.println("Exception Caught in UnsupportedEncodingException catch block");
System.out.println("----------------------------------------");
uee.printStackTrace();
}
httpPost.setEntity(postBody);
HttpResponse response;
try {
response = httpclient.execute(httpPost);
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
System.out.println("Content:" + EntityUtils.toString(entity));
EntityUtils.consume(entity);
// entity.consumeContent();
}
} catch (ClientProtocolException e) {
System.out.println("----------------------------------------");
System.out.println("Exception Caught in ClientProtocolException catch block");
System.out.println("----------------------------------------");
e.printStackTrace();
} catch (IOException e) {
System.out.println("----------------------------------------");
System.out.println("Exception Caught in ClientProtocolException catch block");
System.out.println("----------------------------------------");
e.printStackTrace();
}
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
private static String getXMLDoc() {
StringBuffer XMLDoc = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?><AddressValidationRequest xmlns=\"http://api.mydomain.com/schema/checkout/1.0\">")
.append("<Header><MaxAddressSuggestions>5</MaxAddressSuggestions></Header>")
.append("<Address><Line1>17243 S. Mill Ln</Line1><Line2/><City>Ocean View</City><MainDivision>DE</MainDivision><CountryCode>US</CountryCode><PostalCode>19970</PostalCode></Address>")
.append("</AddressValidationRequest>");
return XMLDoc.toString();
}
}
I am testing HttpClient 4.2 by hitting a mixture of http and https links.
HttpClient seems to stick with the protocol from the first call. If the first call is http, then all following https calls fail but http calls are fine. And vice versa.
Here is the test code I used.
#Test
public void testNoRedirectMixed() throws ClientProtocolException, IOException {
HttpClient httpclient = new DefaultHttpClient();
httpclient=WebClientDevWrapper.wrapClient(httpclient);
HttpClientParams.setRedirecting(httpclient.getParams(), false);
{
HttpGet httpget = new HttpGet("http://www.hotmail.com");
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
assertTrue(EntityUtils.toString(entity).indexOf("com")>0);
}
try {
HttpGet httpget = new HttpGet("https://www.hotmail.com");
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
}catch (Exception e) {
e.printStackTrace();
}
{
HttpGet httpget = new HttpGet("http://www.baidu.com");
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
assertTrue(EntityUtils.toString(entity).indexOf("com")>0);
}
}
The second request (https) will fail, but the baidu request is fine.
Caused by: org.apache.http.HttpException: Unable to establish route: planned = {s}->https://www.hotmail.com; current = {s}->http://www.hotmail.com
at org.apache.http.impl.client.DefaultRequestDirector.establishRoute(DefaultRequestDirector.java:842)
I also have to disable redirection because hotmail redirects request: http://www.hotmail.com -> https://www.hotmail.com or https://www.hotmail.com -> https://www.live.com. A similar error is thrown in either cases.
The wrapper is shown below. It is used to accept all certificates.
public class WebClientDevWrapper {
public static HttpClient wrapClient(HttpClient base) {
try {
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] xcs,
String string) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] xcs,
String string) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
};
ctx.init(null, new TrustManager[] { tm }, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx);
ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ClientConnectionManager ccm = base.getConnectionManager();
SchemeRegistry sr = ccm.getSchemeRegistry();
sr.register(new Scheme("https", ssf, 443));
DefaultHttpClient client= new DefaultHttpClient(ccm, base.getParams());
return client;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
}
HttpClient should be able to manage connections absolutely transparently to the user. This problem is likely to be caused by a regression introduced in the 4.2 release (see HTTPCLIENT-1193).
Use either PoolingConnectionManager or SingleConnectionManager instead of the default one until 4.2.1 version is released.
You are trying to use one connection to communicate to a number of different sites. AFAIR You have to create new connection (== new client) for every unique site.