Failing to handle case when content length is unknown for a REST call
@authorjapps
Situation:
Performing a REST call which does return only HTTP status code without any content and on top of that - does not return any content length as part of the headers.
Issue:
In above scenarios, which is not against the HTTP W3 rules - where content length is not required to be returned as HTTP header; zerocode fails with error as below (see stacktrace)
Solution:
To handle such cases in the code as below When contentlength is unknown: we get -1, then avoid calling upon the IOutils call on the entity
`**long len = httpResponse.getEntity().getContentLength();**
return Response
.status(httpResponse.getStatusLine().getStatusCode())
.entity((entity != null && **len >= 0**) ? IOUtils.toString(entity.getContent(), charset) : null)
.build();`
Let me know if you approve of the suggestion and i can open a PR and deliver the code changes to address this gap.
STRACK TRACE of the ISSUE:
java.io.EOFException: null
at java.util.zip.GZIPInputStream.readUByte(GZIPInputStream.java:268) ~[na:1.8.0_191]
at java.util.zip.GZIPInputStream.readUShort(GZIPInputStream.java:258) ~[na:1.8.0_191]
at java.util.zip.GZIPInputStream.readHeader(GZIPInputStream.java:164) ~[na:1.8.0_191]
at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:79) ~[na:1.8.0_191]
at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:91) ~[na:1.8.0_191]
at org.apache.http.client.protocol.ResponseContentEncoding$1.create(ResponseContentEncoding.java:67) ~[httpclient-4.5.jar:4.5]
at org.apache.http.client.entity.LazyDecompressingInputStream.initWrapper(LazyDecompressingInputStream.java:54) ~[httpclient-4.5.jar:4.5]
at org.apache.http.client.entity.LazyDecompressingInputStream.read(LazyDecompressingInputStream.java:72) ~[httpclient-4.5.jar:4.5]
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284) ~[na:1.8.0_191]
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326) ~[na:1.8.0_191]
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178) ~[na:1.8.0_191]
at java.io.InputStreamReader.read(InputStreamReader.java:184) ~[na:1.8.0_191]
at java.io.Reader.read(Reader.java:140) ~[na:1.8.0_191]
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:2001) ~[commons-io-2.4.jar:2.4]
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1980) ~[commons-io-2.4.jar:2.4]
at org.apache.commons.io.IOUtils.copy(IOUtils.java:1957) ~[commons-io-2.4.jar:2.4]
at org.apache.commons.io.IOUtils.copy(IOUtils.java:1907) ~[commons-io-2.4.jar:2.4]
at org.apache.commons.io.IOUtils.toString(IOUtils.java:778) ~[commons-io-2.4.jar:2.4]
at org.jsmart.zerocode.core.httpclient.BasicHttpClient.createCharsetResponse(BasicHttpClient.java:197) ~[classes/:na]
at org.jsmart.zerocode.core.httpclient.BasicHttpClient.handleResponse(BasicHttpClient.java:160) ~[classes/:na]
at org.jsmart.zerocode.core.httpclient.BasicHttpClient.execute(BasicHttpClient.java:147) ~[classes/:na]
at org.jsmart.zerocode.core.engine.executor.httpapi.HttpApiExecutorImpl.execute(HttpApiExecutorImpl.java:62) ~[classes/:na]
at org.jsmart.zerocode.core.engine.executor.ApiServiceExecutorImpl.executeHttpApi(ApiServiceExecutorImpl.java:34) ~[classes/:na]
at org.jsmart.zerocode.core.runner.ZeroCodeMultiStepsScenarioRunnerImpl.executeApi(ZeroCodeMultiStepsScenarioRunnerImpl.java:411) [classes/:na]
at org.jsmart.zerocode.core.runner.ZeroCodeMultiStepsScenarioRunnerImpl.executeRetry(ZeroCodeMultiStepsScenarioRunnerImpl.java:227) [classes/:na]
at org.jsmart.zerocode.core.runner.ZeroCodeMultiStepsScenarioRunnerImpl.executeRetryWithSteps(ZeroCodeMultiStepsScenarioRunnerImpl.java:178) [classes/:na]
at org.jsmart.zerocode.core.runner.ZeroCodeMultiStepsScenarioRunnerImpl.executeSteps(ZeroCodeMultiStepsScenarioRunnerImpl.java:162) [classes/:na]
at org.jsmart.zerocode.core.runner.ZeroCodeMultiStepsScenarioRunnerImpl.runScenario(ZeroCodeMultiStepsScenarioRunnerImpl.java:125) [classes/:na]
at org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner.runLeafJsonTest(ZeroCodeUnitRunner.java:223) [classes/:na]
at org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner.runChild(ZeroCodeUnitRunner.java:127) [classes/:na]
at org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner.runChild(ZeroCodeUnitRunner.java:51) [classes/:na]
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner.run(ParentRunner.java:363) [junit-4.12.jar:4.12]
at org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner.run(ZeroCodeUnitRunner.java:107) [classes/:na]
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210) [.cp/:na]
java.lang.RuntimeException: java.io.EOFException
at org.jsmart.zerocode.core.engine.executor.ApiServiceExecutorImpl.executeHttpApi(ApiServiceExecutorImpl.java:43)
at org.jsmart.zerocode.core.runner.ZeroCodeMultiStepsScenarioRunnerImpl.executeApi(ZeroCodeMultiStepsScenarioRunnerImpl.java:411)
at org.jsmart.zerocode.core.runner.ZeroCodeMultiStepsScenarioRunnerImpl.executeRetry(ZeroCodeMultiStepsScenarioRunnerImpl.java:227)
at org.jsmart.zerocode.core.runner.ZeroCodeMultiStepsScenarioRunnerImpl.executeRetryWithSteps(ZeroCodeMultiStepsScenarioRunnerImpl.java:178)
at org.jsmart.zerocode.core.runner.ZeroCodeMultiStepsScenarioRunnerImpl.executeSteps(ZeroCodeMultiStepsScenarioRunnerImpl.java:162)
at org.jsmart.zerocode.core.runner.ZeroCodeMultiStepsScenarioRunnerImpl.runScenario(ZeroCodeMultiStepsScenarioRunnerImpl.java:125)
at org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner.runLeafJsonTest(ZeroCodeUnitRunner.java:223)
at org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner.runChild(ZeroCodeUnitRunner.java:127)
at org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner.runChild(ZeroCodeUnitRunner.java:51)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner.run(ZeroCodeUnitRunner.java:107)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: java.io.EOFException
at java.util.zip.GZIPInputStream.readUByte(GZIPInputStream.java:268)
at java.util.zip.GZIPInputStream.readUShort(GZIPInputStream.java:258)
at java.util.zip.GZIPInputStream.readHeader(GZIPInputStream.java:164)
at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:79)
at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:91)
at org.apache.http.client.protocol.ResponseContentEncoding$1.create(ResponseContentEncoding.java:67)
at org.apache.http.client.entity.LazyDecompressingInputStream.initWrapper(LazyDecompressingInputStream.java:54)
at org.apache.http.client.entity.LazyDecompressingInputStream.read(LazyDecompressingInputStream.java:72)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.Reader.read(Reader.java:140)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:2001)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1980)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:1957)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:1907)
at org.apache.commons.io.IOUtils.toString(IOUtils.java:778)
at org.jsmart.zerocode.core.httpclient.BasicHttpClient.createCharsetResponse(BasicHttpClient.java:197)
at org.jsmart.zerocode.core.httpclient.BasicHttpClient.handleResponse(BasicHttpClient.java:160)
at org.jsmart.zerocode.core.httpclient.BasicHttpClient.execute(BasicHttpClient.java:147)
at org.jsmart.zerocode.core.engine.executor.httpapi.HttpApiExecutorImpl.execute(HttpApiExecutorImpl.java:62)
at org.jsmart.zerocode.core.engine.executor.ApiServiceExecutorImpl.executeHttpApi(ApiServiceExecutorImpl.java:34)
... 21 more
@dandalavinod , Thanks for raising this. Can you also paste your Zerocode test steps/scenario if possible?
@nirmalchandra sorry about the delay - was on a break for year end holidays! here is the details you requested
{
"scenarioName": "GIVEN - I make a REST CALL as below, WHEN - call returns 401 http code, no response body where content-length header is also not returned, THEN - I observe Zerocode throw EOFException.",
"ignoreStepFailures" : "true",
"steps": [
{
// This call returns EOFexception
// happens when API returns empty body without setting content-length header.
// There is no REST API guidance as such to always return content-length header
// set along with body for REST API call.
"name": "verify_endpoint_that_returns_401_error",
"url": "${rest.server.url}/Resource/1234",
"method": "GET",
"request": {
"headers": {
"Authorization": "token-xxxx"
}
},
"verify": {
"status": 401
}
}
]
}
I am proposing to add add additional code handling in case of above scenario to understand there might be empty body responses for REST call and handle it in a graceful manner.
Thanks @dandalavinod for the details. Understood the scenario. Yep, the fix looks good.
Please go ahead with the PR. 👍
Please note: Due to the DockerHub rate limit on the image pulls, you need to branch out from the original repo and raise a PR, which will make the CI job to actually run, then turn green. If you have not been added as a collaborator, please give us a shout here, we will add you asap!