Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-41751

Groovy PowerAssertions don't show a useful message when being CPS transformed

    Details

    • Similar Issues:

      Description

      PowerAssertions are a really useful feature of the groovy programming language, as they give you the full information on what is not as it is expected in the error message - the full assert statement with all information about the values.

      However, when running CPS transformed, the output is less useful, as it only states what the assertion was that failed, without the values.
      Take for example the following pipeline script:

      node {
          def a = 4
          stage('without cps') {
              nonCps(a)
          }
      
          stage('with cps') {
              def b = [1, 2, 3]
              try {
                  assert a == b[0]
              } catch (Throwable e) {
                  echo e.class.toString()
                  echo e.message
                  echo e.stackTrace.join('\n')
              }
          }
      }
      
      @NonCPS
      def nonCps(a) {
          def b = [1, 2, 3]
          try {
              assert a == b[0]
          } catch (Throwable e) {
              echo e.class.toString()
              echo e.message
              echo e.stackTrace.join('\n')
          }
      }
      

      Although the code is the same for NonCPS and with CPS,

      NonCPS prints the following:

      assert a == b[0]
             |    |
             |    1
             false
      

      (I.e. the value of the whole expression and the value of b[0],

      while the CPS transformed version prints no information whatsoever:

      assert a == b[0]
      

      N.B.: running the same code in a groovysh actually gives even more information:

      assert a == b[0]
             | |  ||
             4 |  |1
               |  [1, 2, 3]
               false
      

      That one can be worked around by liberally throwing parentheses at the problem, but that again only works in the NonCPS case:

      assert (a == (b[0]))
             ||    ||
             |4    |[1, 2, 3]
             false 1
      

      This makes the assert statement almost useless for writing test jobs for your global library methods, so it would be a really nice addition if the information could be preserved and be added to the message of the PowerAssertionError.

        Attachments

          Issue Links

            Activity

            Hide
            0x89 Martin Sander added a comment -

            N.B. spent some time in a debugger to figure out if this can be easily fixed.

            The cond parameter in https://github.com/cloudbees/groovy-cps/blob/f48c39c41f17565f08f41f11df99adb59af6d2ce/src/main/java/com/cloudbees/groovy/cps/impl/AssertBlock.java#L20 seems to contain (transitive) references to all the data that is needed.
            But I didn't find an easy and general way to get at the values of the local variables and their values, not even for the simple "a == b" case.

            Show
            0x89 Martin Sander added a comment - N.B. spent some time in a debugger to figure out if this can be easily fixed. The cond parameter in https://github.com/cloudbees/groovy-cps/blob/f48c39c41f17565f08f41f11df99adb59af6d2ce/src/main/java/com/cloudbees/groovy/cps/impl/AssertBlock.java#L20 seems to contain (transitive) references to all the data that is needed. But I didn't find an easy and general way to get at the values of the local variables and their values, not even for the simple "a == b" case.
            Hide
            reinholdfuereder Reinhold Füreder added a comment - - edited

            Jesse Glick In the meantime (not sure if it has changed) when having a failing assert in shared pipeline library it leads to build console log like:

            ...
            hudson.remoting.ProxyException: Assertion failed: 
            
            assert wsDir.mkdirs()
            
            	at org.codehaus.groovy.runtime.InvokerHelper.assertFailed(InvokerHelper.java:404)
            	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.assertFailed(ScriptBytecodeAdapter.java:650)
            	at com.cloudbees.groovy.cps.impl.AssertBlock$ContinuationImpl.fail(AssertBlock.java:47)
            	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
            	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            	at java.lang.reflect.Method.invoke(Method.java:498)
            	at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
            	at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
            	at com.cloudbees.groovy.cps.Next.step(Next.java:83)
            	at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174)
            	at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163)
            	at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:122)
            	at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:261)
            	at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163)
            	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$001(SandboxContinuable.java:19)
            	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable$1.call(SandboxContinuable.java:35)
            	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable$1.call(SandboxContinuable.java:32)
            	at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox.runInSandbox(GroovySandbox.java:108)
            	at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:32)
            	at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:174)
            	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:331)
            	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$200(CpsThreadGroup.java:82)
            	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:243)
            	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:231)
            	at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:64)
            	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
            	at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:131)
            	at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
            	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
            	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
            	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
            	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
            	at java.lang.Thread.run(Thread.java:748)
            

            ... and in jenkins log:

            2018-02-15 13:07:00 WARNING [jenkins.security.ClassFilterImpl isBlacklisted]   rejecting org.codehaus.groovy.runtime.powerassert.PowerAssertionError according to standard blacklist; see https://jenkins.io/redirect/class-filter/
            

            => So I think it is even worse now (cf. https://jenkins.io/blog/2018/01/13/jep-200/ and JENKINS-47736), as it does not even state where (stacktrace) the assertion failed?

            Show
            reinholdfuereder Reinhold Füreder added a comment - - edited Jesse Glick In the meantime (not sure if it has changed) when having a failing assert in shared pipeline library it leads to build console log like: ... hudson.remoting.ProxyException: Assertion failed: assert wsDir.mkdirs() at org.codehaus.groovy.runtime.InvokerHelper.assertFailed(InvokerHelper.java:404) at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.assertFailed(ScriptBytecodeAdapter.java:650) at com.cloudbees.groovy.cps.impl.AssertBlock$ContinuationImpl.fail(AssertBlock.java:47) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72) at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21) at com.cloudbees.groovy.cps.Next.step(Next.java:83) at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174) at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163) at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:122) at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:261) at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163) at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$001(SandboxContinuable.java:19) at org.jenkinsci.plugins.workflow.cps.SandboxContinuable$1.call(SandboxContinuable.java:35) at org.jenkinsci.plugins.workflow.cps.SandboxContinuable$1.call(SandboxContinuable.java:32) at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox.runInSandbox(GroovySandbox.java:108) at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:32) at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:174) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:331) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$200(CpsThreadGroup.java:82) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:243) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:231) at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:64) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:131) at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) ... and in jenkins log: 2018-02-15 13:07:00 WARNING [jenkins.security.ClassFilterImpl isBlacklisted] rejecting org.codehaus.groovy.runtime.powerassert.PowerAssertionError according to standard blacklist; see https://jenkins.io/redirect/class-filter/ => So I think it is even worse now (cf. https://jenkins.io/blog/2018/01/13/jep-200/ and JENKINS-47736 ), as it does not even state where (stacktrace) the assertion failed?
            Hide
            oleg_nenashev Oleg Nenashev added a comment -

            Reinhold Füreder please set JEP-200 label next time you see such warning. I was lucky to see this ticket

            Show
            oleg_nenashev Oleg Nenashev added a comment - Reinhold Füreder please set JEP-200 label next time you see such warning. I was lucky to see this ticket
            Hide
            jglick Jesse Glick added a comment -

            I filed a fix for this four weeks ago and it was approved but not merged.

            Show
            jglick Jesse Glick added a comment - I filed a fix for this four weeks ago and it was approved but not merged.
            Hide
            abayer Andrew Bayer added a comment -
            Show
            abayer Andrew Bayer added a comment - Jesse Glick Link?
            Hide
            reinholdfuereder Reinhold Füreder added a comment -

            Oleg Nenashev Yes, sir! Err, I meant sorry, will do...
            Jesse Glick Awesome response/fix time! Thanks!

            Show
            reinholdfuereder Reinhold Füreder added a comment - Oleg Nenashev Yes, sir! Err, I meant sorry, will do... Jesse Glick Awesome response/fix time! Thanks!

              People

              • Assignee:
                jglick Jesse Glick
                Reporter:
                0x89 Martin Sander
              • Votes:
                0 Vote for this issue
                Watchers:
                5 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: