Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apache HttpClient + WireMock #41

Closed
maybeec opened this issue Jul 2, 2013 · 18 comments
Closed

Apache HttpClient + WireMock #41

maybeec opened this issue Jul 2, 2013 · 18 comments

Comments

@maybeec
Copy link

maybeec commented Jul 2, 2013

Hi,

I have observed strange behavior when accessing a mocked server instance of WireMock with the Apache HttpClient.
When I debug the test, and go to the mocked server address in my browser, I got the expected response. However accessing the same address with the Apache HttpClient leads to a 404 response.

Necessary Information about the Test (not the whole test, only WireMock related configurations):

 @RunWith(SpringJUnit4ClassRunner.class)
 public class Test {

    @Rule
    public WireMockRule wireMockRule = new WireMockRule(9999);

    @Before
    public void reset() {
        WireMock.reset();
    }

    @Test
    public void test() {
        String request = "Any Request";
        stubFor(get(urlEqualTo("/")).willReturn(aResponse().withStatus(200).withBody(response.getBytes())));

        verify(postRequestedFor(urlEqualTo("/"))
            .withHeader("Content-Type", equalTo("text/xml; charset=UTF-8"))
            .withHeader("SOAPAction", equalTo("")).withRequestBody(equalTo(request)));
     }
 }

Nice to know is, that the verification is valid. So the mock is obviously called correctly.

HttpClient-Code calling the mocked server address:

HttpClient client = new DefaultHttpClient();
ByteArrayEntity requestEntity = new ByteArrayEntity(_requestStr_.getBytes());
requestEntity.setContentType("text/xml; charset=UTF-8");
requestEntity.setContentEncoding("UTF-8");

HttpPost httpPost = new HttpPost("http://localhost:9999");
httpPost.addHeader("SOAPAction", "");
httpPost.setEntity(requestEntity);
HttpResponse response = client.execute(httpPost);

HttpEntity entity = response.getEntity();
if (entity != null) {
    InputStream in = entity.getContent();
    try {
        System.out.print(new String(IOUtils.toByteArray(in)));
    } finally {
        in.close();
    }
}

Now I got the 404 Error html page from jetty, although the browser shows the right mocked response:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<title>Error 404 NOT_FOUND</title>
</head>
<body><h2>HTTP ERROR 404</h2>
<p>Problem accessing /. Reason:
<pre>    NOT_FOUND</pre></p><hr /><i><small>Powered by Jetty://</small></i><br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                

</body>
</html>

Any suggestions why I got the right answer in my firefox browser and got a 404 via the Apache HttpClient? Perhaps are there any headers which are assumed to be in the request in order to let WireMock match the called URL and provide a declared response?

@tomakehurst
Copy link
Member

I'm lacking access to a computer at the moment so I can't test this but it could be because your stub definition has a trailing slash but your http post doesn't

BTW, your @before block is unnecessary as reset() is called by the rule.

@maybeec
Copy link
Author

maybeec commented Jul 3, 2013

I've added the trailing slash to the HttpPost

HttpPost httpPost = new HttpPost("http://localhost:9999/");

Unfortunately this does not solve the problem.

@tomakehurst
Copy link
Member

If you add a log4j notifier to the options passed to the rule and set it to verbose it'll log out why it didn't match at INFO.

@maybeec
Copy link
Author

maybeec commented Jul 4, 2013

After adding the log4j Notifier as follows

@Rule
    public WireMockRule wireMockRule = new WireMockRule(wireMockConfig().port(testPort).notifier(
        new Log4jNotifier()));

I got no more information, but several NullPointerExceptions :) Perhaps a bug?

[D: 2013-07-04 10:50:26,883] [P: INFO ] [T: 15087110@qtp-26116262-0] [L: /__admin] - [M: RequestHandlerClass from context returned com.github.tomakehurst.wiremock.http.AdminRequestHandler] 
[D: 2013-07-04 10:50:27,367] [P: INFO ] [T: 31003492@qtp-26116262-2] [L: /] - [M: RequestHandlerClass from context returned com.github.tomakehurst.wiremock.http.StubRequestHandler] 
[D: 2013-07-04 10:50:27,508] [P: ERROR] [T: main] [L: org.mortbay.log] - [M: EXCEPTION ] 
java.lang.NullPointerException
    at javax.servlet.GenericServlet.getServletContext(GenericServlet.java:205)
    at javax.servlet.GenericServlet.log(GenericServlet.java:300)
    at javax.servlet.GenericServlet.destroy(GenericServlet.java:122)
    at org.mortbay.jetty.servlet.ServletHolder.destroyInstance(ServletHolder.java:318)
    at org.mortbay.jetty.servlet.ServletHolder.doStop(ServletHolder.java:289)
    at org.mortbay.component.AbstractLifeCycle.stop(AbstractLifeCycle.java:76)
    at org.mortbay.jetty.servlet.ServletHandler.doStop(ServletHandler.java:185)
    at org.mortbay.component.AbstractLifeCycle.stop(AbstractLifeCycle.java:76)
    at org.mortbay.jetty.handler.HandlerWrapper.doStop(HandlerWrapper.java:142)
    at org.mortbay.jetty.handler.ContextHandler.doStop(ContextHandler.java:592)
    at org.mortbay.component.AbstractLifeCycle.stop(AbstractLifeCycle.java:76)
    at org.mortbay.jetty.handler.HandlerCollection.doStop(HandlerCollection.java:169)
    at org.mortbay.component.AbstractLifeCycle.stop(AbstractLifeCycle.java:76)
    at org.mortbay.jetty.handler.HandlerWrapper.doStop(HandlerWrapper.java:142)
    at org.mortbay.jetty.Server.doStop(Server.java:283)
    at org.mortbay.component.AbstractLifeCycle.stop(AbstractLifeCycle.java:76)
    at com.github.tomakehurst.wiremock.WireMockServer.stop(WireMockServer.java:148)
    at com.github.tomakehurst.wiremock.junit.WireMockRule$1.evaluate(WireMockRule.java:66)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
[D: 2013-07-04 10:50:27,508] [P: ERROR] [T: main] [L: org.mortbay.log] - [M: EXCEPTION ] 
java.lang.NullPointerException
    at javax.servlet.GenericServlet.getServletContext(GenericServlet.java:205)
    at javax.servlet.GenericServlet.log(GenericServlet.java:300)
    at javax.servlet.GenericServlet.destroy(GenericServlet.java:122)
    at org.mortbay.jetty.servlet.ServletHolder.destroyInstance(ServletHolder.java:318)
    at org.mortbay.jetty.servlet.ServletHolder.doStop(ServletHolder.java:289)
    at org.mortbay.component.AbstractLifeCycle.stop(AbstractLifeCycle.java:76)
    at org.mortbay.jetty.servlet.ServletHandler.doStop(ServletHandler.java:185)
    at org.mortbay.component.AbstractLifeCycle.stop(AbstractLifeCycle.java:76)
    at org.mortbay.jetty.handler.HandlerWrapper.doStop(HandlerWrapper.java:142)
    at org.mortbay.jetty.handler.ContextHandler.doStop(ContextHandler.java:592)
    at org.mortbay.component.AbstractLifeCycle.stop(AbstractLifeCycle.java:76)
    at org.mortbay.jetty.handler.HandlerCollection.doStop(HandlerCollection.java:169)
    at org.mortbay.component.AbstractLifeCycle.stop(AbstractLifeCycle.java:76)
    at org.mortbay.jetty.handler.HandlerWrapper.doStop(HandlerWrapper.java:142)
    at org.mortbay.jetty.Server.doStop(Server.java:283)
    at org.mortbay.component.AbstractLifeCycle.stop(AbstractLifeCycle.java:76)
    at com.github.tomakehurst.wiremock.WireMockServer.stop(WireMockServer.java:148)
    at com.github.tomakehurst.wiremock.junit.WireMockRule$1.evaluate(WireMockRule.java:66)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

@tomakehurst
Copy link
Member

I think that exception is probably because you've got an additional, different version of the servlet API on your classpath. If you try excluding this (temporarily at least) so that only the Servlet API version pulled in via WireMock is present, this should go away.

@tomakehurst
Copy link
Member

Looks like the same exception as in this issue (for which excluding the other Servlet API solved the issue):
https://github.com/tomakehurst/wiremock/issues/37

@maybeec
Copy link
Author

maybeec commented Jul 4, 2013

Ok. the servlet issue solved the problem for debugging.
Now I get

[D: 2013-07-04 14:28:08,772] [P: INFO ] [T: 26116262@qtp-32879825-0] [L: /__admin] - [M: RequestHandlerClass from context returned com.github.tomakehurst.wiremock.http.AdminRequestHandler] 
[D: 2013-07-04 14:28:09,232] [P: INFO ] [T: 17621911@qtp-32879825-2] [L: /] - [M: RequestHandlerClass from context returned com.github.tomakehurst.wiremock.http.StubRequestHandler]

thats all.... no additional information.
Remember, "verify" verifies the request done by the tested code snippet as follows

verify(postRequestedFor(urlEqualTo("/"))
            .withHeader("Content-Type", equalTo("text/xml; charset=UTF-8"))
            .withHeader("SOAPAction", equalTo("")).withRequestBody(equalTo(request)));

@tomakehurst
Copy link
Member

Probably because you're running with log4j defaults. Try calling Log4jConfigurer.configure (true); in your @before

@maybeec
Copy link
Author

maybeec commented Jul 4, 2013

I do not use the default log4j properties, but I saw there is a restriction for com.* packages set to WARN :) So I changed this and get the following:

[D: 2013-07-04 14:49:28,252] [P: WARN ] [T: main] [L: org.dozer.config.GlobalSettings] - [M: Dozer configuration file not found: dozer.properties.  Using defaults for all Dozer global properties.] 
[D: 2013-07-04 14:49:29,003] [P: INFO ] [T: 15087110@qtp-26116262-0] [L: /__admin] - [M: RequestHandlerClass from context returned com.github.tomakehurst.wiremock.http.AdminRequestHandler] 
[D: 2013-07-04 14:49:29,013] [P: INFO ] [T: 15087110@qtp-26116262-0] [L: com.github.tomakehurst.wiremock.common.Log4jNotifier] - [M: Received request to /mappings/new with body {
  "request" : {
    "url" : "/",
    "method" : "GET"
  },
  "response" : {
    "status" : 200,
    "base64Body" : "QW55IFJlc3BvbnNlIDA="
  }
}] 
[D: 2013-07-04 14:49:29,433] [P: INFO ] [T: 31003492@qtp-26116262-2] [L: /] - [M: RequestHandlerClass from context returned com.github.tomakehurst.wiremock.http.StubRequestHandler] 
[D: 2013-07-04 14:49:29,433] [P: INFO ] [T: 31003492@qtp-26116262-2] [L: com.github.tomakehurst.wiremock.common.Log4jNotifier] - [M: Received request to /] 
[D: 2013-07-04 14:49:29,433] [P: INFO ] [T: 31003492@qtp-26116262-2] [L: com.github.tomakehurst.wiremock.common.Log4jNotifier] - [M: URL / is match, but method POST is not] 
[D: 2013-07-04 14:49:29,433] [P: INFO ] [T: 31003492@qtp-26116262-2] [L: com.github.tomakehurst.wiremock.common.Log4jNotifier] - [M: No mapping found matching URL /] 
[D: 2013-07-04 14:49:29,504] [P: INFO ] [T: 15087110@qtp-26116262-0] [L: com.github.tomakehurst.wiremock.common.Log4jNotifier] - [M: Received request to /requests/count with body {
  "url" : "/",
  "method" : "POST",
  "bodyPatterns" : [ {
    "equalTo" : "Any Request 0"
  } ],
  "headers" : {
    "Content-Type" : {
      "equalTo" : "text/xml; charset=UTF-8"
    },
    "SOAPAction" : {
      "equalTo" : ""
    }
  }
}] 

@tomakehurst
Copy link
Member

Ok, it looks like you've configured your stub for a GET only but are hitting it with a POST.

@tomakehurst
Copy link
Member

Which version are you running?

@maybeec
Copy link
Author

maybeec commented Jul 4, 2013

I am running v1.33 of WireMock. Where do I can configure the stub for POST requests?

@maybeec
Copy link
Author

maybeec commented Jul 5, 2013

Wow, some hours of sleep make the job :)
It is the post before the url matcher which does this job...

post(urlEqualTo("/")

As the term 'get', which is used in each example in the documentation, is some kind of overloaded in this case, in my opinion, the documentation should be a little bit clearer here :)

Nevertheless, thanks for you quick and helpful feedback and also thanks for WireMock! I love it! 👍

@maybeec maybeec closed this as completed Jul 5, 2013
@JuliaIskra
Copy link

Hello, @tomakehurst !

Looks like I have the same problem - conflicted Http Client dependency.
As I understand from documentation this:

<classifier>standalone</classifier>

should solve the problem, but it is not.

How can I fix it?

@tomakehurst
Copy link
Member

Yes, the docs aren't great in this regard.

The POM with the standalone version still (currently) pulls in the transitive dependencies, so you need to explicitly exclude the ones that are causing you problems e.g.

<exclusions>
  <exclusion>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
  </exclusion>
</exclusions>

@JuliaIskra
Copy link

No, this doesn't help.

I'm still getting ERROR 404

@JuliaIskra
Copy link

Sorry, I was thoughtless :)
Found the bug - it's the same as @may-bee had - get instead post

Thank you!

@sensoryorgan
Copy link

@tomakehurst Is it possible to exclude certain query parameter while running wiremock standalone?
tobe more precise while invoking an url e.g. http:\search.twitter.com?userid=1236524&name=stella&date=....
Can I do it in a way so that for all the urls invoked "userid" would not be considered while recording the response. So that if userid changes and rest of the url remains same, wiremock wont record the response again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants