allure-framework / allure-java

Allure integrations for Java test frameworks
Apache License 2.0
352 stars 223 forks source link

[allure-restassured] Could't render http attachment file #784

Open tolbala opened 2 years ago

tolbala commented 2 years ago

Describe the bug The response couldn't be attached to the allure report.

io.qameta.allure.attachment.AttachmentRenderException: Could't render http attachment file at io.qameta.allure.attachment.FreemarkerAttachmentRenderer.render(FreemarkerAttachmentRenderer.java:49) at io.qameta.allure.attachment.FreemarkerAttachmentRenderer.render(FreemarkerAttachmentRenderer.java:28) at io.qameta.allure.attachment.DefaultAttachmentProcessor.addAttachment(DefaultAttachmentProcessor.java:41) at io.qameta.allure.restassured.AllureRestAssured.filter(AllureRestAssured.java:119) at io.restassured.filter.Filter$filter.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:46) at io.restassured.filter.Filter$filter.call(Unknown Source) at io.restassured.internal.filter.FilterContextImpl.next(FilterContextImpl.groovy:72) at io.restassured.filter.log.StatusCodeBasedLoggingFilter.filter(StatusCodeBasedLoggingFilter.java:112) at io.restassured.filter.log.ResponseLoggingFilter.filter(ResponseLoggingFilter.java:31) at io.restassured.filter.Filter$filter.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:46) at io.restassured.filter.Filter$filter.call(Unknown Source) at io.restassured.internal.filter.FilterContextImpl.next(FilterContextImpl.groovy:72) at io.restassured.filter.log.RequestLoggingFilter.filter(RequestLoggingFilter.java:146) at io.restassured.filter.Filter$filter.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:46) at io.restassured.filter.Filter$filter.call(Unknown Source) at io.restassured.internal.filter.FilterContextImpl.next(FilterContextImpl.groovy:72) at ........Filters.lambda$requestAndResponseFilter$0(Filters.java:19) at io.restassured.filter.Filter$filter.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:46) at io.restassured.filter.Filter$filter$0.call(Unknown Source) at io.restassured.internal.filter.FilterContextImpl.next(FilterContextImpl.groovy:72) at io.restassured.filter.FilterContext$next.call(Unknown Source) at io.restassured.internal.RequestSpecificationImpl.applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy:1686) at io.restassured.internal.RequestSpecificationImpl.this$2$applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy) at jdk.internal.reflect.GeneratedMethodAccessor124.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:328) at groovy.lang.MetaClassImpl.doInvokeMethod(MetaClassImpl.java:1369) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1103) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1009) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:792) at io.restassured.internal.RequestSpecificationImpl.invokeMethod(RequestSpecificationImpl.groovy) at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.call(PogoInterceptableSite.java:46) at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.callCurrent(PogoInterceptableSite.java:57) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:203) at io.restassured.internal.RequestSpecificationImpl.applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy:1692) at io.restassured.internal.RequestSpecificationImpl.this$2$applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy) at jdk.internal.reflect.GeneratedMethodAccessor123.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:328) at groovy.lang.MetaClassImpl.doInvokeMethod(MetaClassImpl.java:1369) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1103) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1009) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:792) at io.restassured.internal.RequestSpecificationImpl.invokeMethod(RequestSpecificationImpl.groovy) at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.call(PogoInterceptableSite.java:46) at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.callCurrent(PogoInterceptableSite.java:57) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:203) at io.restassured.internal.RequestSpecificationImpl.get(RequestSpecificationImpl.groovy:176) at io.restassured.internal.RequestSpecificationImpl.get(RequestSpecificationImpl.groovy) ....... at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725) at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) at io.qameta.allure.junit5.AllureJunit5.interceptTestTemplateMethod(AllureJunit5.java:59) at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115) at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149) at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140) at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestTemplateMethod(TimeoutExtension.java:92) at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115) at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104) at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.compute(ForkJoinPoolHierarchicalTestExecutorService.java:185) at org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService.submit(ForkJoinPoolHierarchicalTestExecutorService.java:118) at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:226) at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:204) at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:139) at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.lambda$execute$2(TestTemplateTestDescriptor.java:107) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:107) at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:42) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.compute(ForkJoinPoolHierarchicalTestExecutorService.java:185) at java.base/java.util.concurrent.RecursiveAction.exec(RecursiveAction.java:194) at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373) at java.base/java.util.concurrent.ForkJoinTask.awaitDone(ForkJoinTask.java:436) at java.base/java.util.concurrent.ForkJoinTask.join(ForkJoinTask.java:670) at org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService.joinConcurrentTasksInReverseOrderToEnableWorkStealing(ForkJoinPoolHierarchicalTestExecutorService.java:162) at org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService.invokeAll(ForkJoinPoolHierarchicalTestExecutorService.java:136) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.compute(ForkJoinPoolHierarchicalTestExecutorService.java:185) at java.base/java.util.concurrent.RecursiveAction.exec(RecursiveAction.java:194) at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373) at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182) at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655) at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622) at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165) Caused by: java.lang.IndexOutOfBoundsException: start 333, end 0, length 2218 at java.base/java.lang.AbstractStringBuilder.checkRange(AbstractStringBuilder.java:1802) at java.base/java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:680) at java.base/java.lang.StringBuffer.append(StringBuffer.java:388) at java.base/java.io.StringWriter.write(StringWriter.java:122) at freemarker.template.utility.StringUtil.XMLOrHTMLEnc(StringUtil.java:215) at freemarker.template.utility.StringUtil.XHTMLEnc(StringUtil.java:105) at freemarker.core.HTMLOutputFormat.output(HTMLOutputFormat.java:62) at freemarker.core.DollarVariable.accept(DollarVariable.java:68) at freemarker.core.Environment.visit(Environment.java:347) at freemarker.core.Environment.visit(Environment.java:353) at freemarker.core.Environment.visit(Environment.java:353) at freemarker.core.Environment.process(Environment.java:326) at freemarker.template.Template.process(Template.java:383) at io.qameta.allure.attachment.FreemarkerAttachmentRenderer.render(FreemarkerAttachmentRenderer.java:46) ... 169 more

Expected behaviour The response is successfully attached to the allure report or the filter is ignored by RestAssured if it throws an exception.

Versions Java version: openjdk 17.0.2 Maven: 3.8.4

allure-junit5:2.17.3 rest-assured:4.3.3 allure-rest-assured:2.17.3 junit-jupiter-params:5.7.0 allure-maven:2.11.2 aspectjweaver:1.9.8

Additional info Tests are executed in parallel. The issue cannot be reproduced constantly. The issue occurred when the size of the response was large.

martinsefcik commented 2 years ago

It is randomly happing also to us and it is really annoying. Sometimes it fails , sometimes it passes with the same response body. I spend a lot of time digging in the code but I was not able to identify if it is issue on Allure side or Freemarker side or somewhere else.

For example for us it is very often failing with the following response body

{
    "message": "Token claims invalid: [\"exp\"]=\"token expired\""
}

with exception:

....
Caused by: java.lang.IndexOutOfBoundsException: start 67, end 0, length 70
    at java.base/java.lang.AbstractStringBuilder.checkRange(AbstractStringBuilder.java:1802)
    at java.base/java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:680)
    at java.base/java.lang.StringBuffer.append(StringBuffer.java:393)
    at java.base/java.io.StringWriter.write(StringWriter.java:122)
    at freemarker.template.utility.StringUtil.XMLOrHTMLEnc(StringUtil.java:215)
    at freemarker.template.utility.StringUtil.XHTMLEnc(StringUtil.java:105)
    at freemarker.core.HTMLOutputFormat.output(HTMLOutputFormat.java:62)
    at freemarker.core.DollarVariable.accept(DollarVariable.java:68)
    at freemarker.core.Environment.visit(Environment.java:347)
    at freemarker.core.Environment.visit(Environment.java:353)
    at freemarker.core.Environment.visit(Environment.java:353)
    at freemarker.core.Environment.process(Environment.java:326)
    at freemarker.template.Template.process(Template.java:383)
    at io.qameta.allure.attachment.FreemarkerAttachmentRenderer.render(FreemarkerAttachmentRenderer.java:46)

And if start = 67 and end = 0 in java.base/java.lang.AbstractStringBuilder.checkRange then on line 215 in freemarker.template.utility.StringUtil.XMLOrHTMLEnc method writtenEnd must be 67 and flushLn must -67 and based on the algorithm in freemarker.template.utility.StringUtil.XMLOrHTMLEnc method I guess it cannot happen. So it is weird.

We are not running tests in parallel. It is quite often happening with this specific response I provided hereinbefore. Rarely with larger responses.

We are using: Allure 2.18.1 => Freemarker 2.3.31 Junit 5.8.2

tolbala commented 2 years ago

@martinsefcik I've implemented a workaround that basically just catches the exception and adds some logs to the report. The implementation is almost the same as it is in the allure-restassured lib, but the execution won't fail due to the rendering exception.

public static Filter safeAllureRestAssured() {

        return (reqSpec, respSpec, ctx) -> {
            final Response response = ctx.next(reqSpec, respSpec);
            final Prettifier prettifier = new Prettifier();
            final String url = reqSpec.getURI();

            final HttpRequestAttachment.Builder requestAttachmentBuilder = create("Request", url)
                .setMethod(reqSpec.getMethod())
                .setHeaders(toMapConverter(reqSpec.getHeaders()))
                .setCookies(toMapConverter(reqSpec.getCookies()));

            if (Objects.nonNull(reqSpec.getBody())) {
                requestAttachmentBuilder.setBody(prettifier.getPrettifiedBodyIfPossible(reqSpec));
            }

            final HttpRequestAttachment requestAttachment = requestAttachmentBuilder.build();
            try {
                new DefaultAttachmentProcessor().addAttachment(
                    requestAttachment,
                    new FreemarkerAttachmentRenderer("http-request.ftl")
                );
            } catch (AttachmentRenderException ignore) {
                log.error("AttachmentRenderException occurred during attaching the request to the report.");
                attachLogs("Request", getRequestLog(requestAttachment));
            }

            String responseAttachmentName = response.getStatusLine();

            final HttpResponseAttachment responseAttachment = HttpResponseAttachment.Builder.create(
                responseAttachmentName
            )
                .setResponseCode(response.getStatusCode())
                .setHeaders(toMapConverter(response.getHeaders()))
                .setBody(prettifier.getPrettifiedBodyIfPossible(response, response.getBody()))
                .build();

            try {
                new DefaultAttachmentProcessor().addAttachment(
                    responseAttachment,
                    new FreemarkerAttachmentRenderer("http-response.ftl")
                );
            } catch (AttachmentRenderException e) {
                log.error("AttachmentRenderException occurred during attaching the Response to the report.");
                attachLogs("Response", getResponseLog(responseAttachment));
            }

            return response;
        };
    }

Usage: RestAssured.replaceFiltersWith(Filters.safeAllureRestAssured());

martinsefcik commented 2 years ago

@tolbala Thank you for workaround. Could you also provide implementation for attachLogs(), getRequestLog() and getResponseLog() methods ?

tolbala commented 2 years ago

@martinsefcik Here you can find the implementation of the missing methods:

 private static String getRequestLog(HttpRequestAttachment requestAttachment) {
        return """
                Method: %s
                URL: %s
                Body: %s
                """.formatted(
            requestAttachment.getMethod(),
            requestAttachment.getUrl(),
            requestAttachment.getBody()
        );
    }

    private static String getResponseLog(HttpResponseAttachment responseAttachment) {
        return """
                Status Code: %s
                Body: %s
                """.formatted(
            responseAttachment.getResponseCode(),
            responseAttachment.getBody()
        );
    }

    private static void attachLogs(String name, String content) {
        Allure.getLifecycle()
            .addAttachment(
                name,
                "text/plain",
                "txt",
                content.getBytes(StandardCharsets.UTF_8)
            );
    }

I've spent a couple of hours debugging the code, trying different combinations of the lib versions(allure, restassured, allure-restassured, etc.), but I was unable to reproduce the issue constantly so I don't know what causes the issue.

mmcdermo2 commented 1 year ago

We've started encountering this issue last week too and are pretty stumped on what could be causing it. From our troubleshooting so far we've determined

I've tried creating a test project which sends an identical request to https://reqres.in over and over again, and yet I can't reproduce the issue there. No idea why, And a search on the freemarker github repo for IndexOutOfBoundsException reveals zero results :-(

Versions

martinsefcik commented 1 year ago

@mmcdermo2 for us it was also failing on libericaJDK 17

NewbieProger commented 1 year ago

We have such problem too.

Java Liberica 17 Cucumber 7 rest-assured 5.2.0 allure-rest-assured 2.19.0

pavelicii commented 1 year ago

Got this error too.

Java 17 rest-assured 5.3.1 allure-rest-assured 2.23.0 alure-gradle-plugin 2.11.2 (no Cucumber)

martinsefcik commented 1 year ago

@pavelicii Which JDK distribution? Liberica?

pavelicii commented 1 year ago

@martinsefcik Oracle JDK.

wavesrcomn commented 12 months ago

We have got the same error too. Java 17.0.8 Gradle 7.3 Junit 5.8.2 Rest assured 4.5.0 Allure 2.20.0 Allure Gradle plugin 2.11.0

This error happens only if we run tests in CI (image based on linux (alpine) with java and gradle), for local runs everything is ok. We use junit multitheaded run:

"junit.jupiter.extensions.autodetection.enabled": true,
"junit.jupiter.execution.parallel.enabled": true,
"junit.jupiter.execution.parallel.mode.default": "same_thread",
"junit.jupiter.execution.parallel.mode.classes.default": "concurrent"
sokolek commented 11 months ago

@martinsefcik Have you been able to re-create the problem in any reproducible way on local machine, on host or docker container? I've observed exactly same problem, on AWS ECS container running ubuntu 20.04 with eclipse temurin 17.0.3_7-jre. We do not use allure, we use freemarker to generate some html based on a template. Top of the stack trace is however the same, call to freemarker.template.utility.StringUtil.XMLOrHTMLEnc(StringUtil.java:215) ends with IndexOutOfBoundsException where end is 0, and start > 0.

I also spent some time analyzing codes and I have same observarions like you: So considering https://github.com/apache/freemarker/blob/v2.3.31/src/main/java/freemarker/template/utility/StringUtil.java#L215 and java.lang.IndexOutOfBoundsException: start 67, end 0, length 70

i, writtenEnd, flushLn are local variables and there are no other threads spawn inside the method. This also applies to StringBuilder etc. This makes me thinking it could be JIT or instrumentation related. However it is hard to confirm that, as it happened only once. Do you use some unusual JVM flags, java agents or instrumentation methods? Does it happened only in cloud? Does the exception is always thrown from this line: https://github.com/apache/freemarker/blob/v2.3.31/src/main/java/freemarker/template/utility/StringUtil.java#L215 and never from this one: https://github.com/apache/freemarker/blob/v2.3.31/src/main/java/freemarker/template/utility/StringUtil.java#L229 ? What exactly java 17 version do you use? (build)

RasmusSoot commented 10 months ago

Upgrading Java version fixed this issue for me. Flaky version was with maven:3.8-openjdk-17 Docker image, Java version: 17.0.2, vendor: Oracle Corporation Upgrade to maven:3.9-eclipse-temurin-17 Docker image, Java version: 17.0.8.1, vendor: Eclipse Adoptium

Sample request body with empty quotation marks "":

{
    "status": 200,
    "headers": {
        "Content-Type": "application/json"
    },
    "responseBody": ""
}

Sample error, always on StringUtil.java line 215:

Caused by: java.lang.IndexOutOfBoundsException: start 109, end 0, length 112
    at java.base/java.lang.AbstractStringBuilder.checkRange(AbstractStringBuilder.java:1802)
    at java.base/java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:680)
    at java.base/java.lang.StringBuffer.append(StringBuffer.java:393)
    at java.base/java.io.StringWriter.write(StringWriter.java:122)
    at freemarker.template.utility.StringUtil.XMLOrHTMLEnc(StringUtil.java:215)
    at freemarker.template.utility.StringUtil.XHTMLEnc(StringUtil.java:105)