groovy
  1. groovy
  2. GROOVY-3851

@Grapes does not work (at least not in Groovy Console)

    Details

    • Type: Bug Bug
    • Status: Closed Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.6.5
    • Fix Version/s: 1.6.6, 1.7-rc-1
    • Component/s: Grape
    • Labels:
      None
    • Environment:
      Mac OS 10.6.1
      Java 1.6.0_15
    • Testcase included:
      yes
    • Number of attachments :
      1

      Description

      Try this in Groovy Console:

      @Grapes(
        [@Grab(group='org.spockframework', module='spock-core', version='0.2'),
        @Grab(group="junit", module="junit", version="4.7")])
      class HelloSpock extends Specification {
       def "can you figure out what I'm up to?"() {
         expect:
         name.size() == length
      
         where:
         name << ["Kirk", "Spock", "Scotty"]
         length << [4, 5, 6]
       }
      }
      

      Output:

      1 compilation error:
      
      unable to resolve class Specification 
       at line: 1, column: 1
      

      This means that Spock is not on the compile class path. When I @Grab JUnit and Spock individually by introducing a fake class, script works as expected. (Well, not quite. I need to add JUnitCore.run(HelloSpock) because otherwise, the test class is no longer found.)

      By the way, if Ivy was fully compatible with Maven, the JUnit @Grab wouldn't be necessary, because JUnit is a mandatory compile-time dependency of Spock. Admittedly, Ivy's transitive dependency resolution is more correct than Maven's, but at the cost of breaking compatibility. Is there a way to tweak this?

        Issue Links

          Activity

          Hide
          Roshan Dawrani added a comment -

          I don't think that the compilation error you are getting here is due to any Grape bug. Your script should be like:

          import spock.lang.Specification
          
          @Grapes(
            [@Grab(group='org.spockframework', module='spock-core', version='0.2'),
            @Grab(group="junit", module="junit", version="4.7")])
          class HelloSpock extends Specification {
          .....
          }
          

          Since spock.lang.* package is not a default import into groovy, you need to tell in the script which package class Specification could be found in.

          Also, looking at the grape executing your script, I noticed that it was retrieving junit-4.6 correctly as the dependency, so you should not need @Grab JUnit.

          Can you first try with the spock.lang.Specification and then without the Junit @Grab?

          Show
          Roshan Dawrani added a comment - I don't think that the compilation error you are getting here is due to any Grape bug. Your script should be like: import spock.lang.Specification @Grapes( [@Grab(group='org.spockframework', module='spock-core', version='0.2'), @Grab(group= "junit" , module= "junit" , version= "4.7" )]) class HelloSpock extends Specification { ..... } Since spock.lang.* package is not a default import into groovy, you need to tell in the script which package class Specification could be found in. Also, looking at the grape executing your script, I noticed that it was retrieving junit-4.6 correctly as the dependency, so you should not need @Grab JUnit. Can you first try with the spock.lang.Specification and then without the Junit @Grab?
          Hide
          Peter Niederwieser added a comment -

          I think I just lost the import at some point when investigating this issue. After fixing the import, I'm back at:

          Exception thrown: org.junit.runner.JUnitCore
          
          java.lang.ClassNotFoundException: org.junit.runner.JUnitCore
          

          That's what you see after my recent commit in trunk. Otherwise you'll just get "Error running JUnit 4 test." Adding the JUnit @Grab with @Grapes doesn't make a difference, but adding it on a fake class solves the ClassNotFoundException problem:

          import spock.lang.*
          
          @Grab(group="junit", module="junit", version="4.7")
          class Fake {}
          
          @Grab(group='org.spockframework', module='spock-core', version='0.2')
          class HelloSpock extends Specification {
          def "can you figure out what I'm up to?"() {
            expect:
            name.size() == length
          
            where:
            name << ["Kirk", "Spock", "Scotty"]
            length << [4, 5, 6]
          }
          }
          
          // we have to run the spec manually because GroovyShell doesn't know what to do if two classes are present
          new org.junit.runner.JUnitCore().run(HelloSpock).failureCount
          
          Show
          Peter Niederwieser added a comment - I think I just lost the import at some point when investigating this issue. After fixing the import, I'm back at: Exception thrown: org.junit.runner.JUnitCore java.lang.ClassNotFoundException: org.junit.runner.JUnitCore That's what you see after my recent commit in trunk. Otherwise you'll just get "Error running JUnit 4 test." Adding the JUnit @Grab with @Grapes doesn't make a difference, but adding it on a fake class solves the ClassNotFoundException problem: import spock.lang.* @Grab(group= "junit" , module= "junit" , version= "4.7" ) class Fake {} @Grab(group='org.spockframework', module='spock-core', version='0.2') class HelloSpock extends Specification { def "can you figure out what I'm up to?" () { expect: name.size() == length where: name << [ "Kirk" , "Spock" , "Scotty" ] length << [4, 5, 6] } } // we have to run the spec manually because GroovyShell doesn't know what to do if two classes are present new org.junit.runner.JUnitCore().run(HelloSpock).failureCount
          Hide
          Roshan Dawrani added a comment -

          I tried a change with which the following script is working fine (but only from 2nd attempt onwards - details follow).

          import spock.lang.*
          
          @Grab(group='org.spockframework', module='spock-core', version='0.2')
          class HelloSpock extends Specification {
           def "can you figure out what I'm up to?"() {
             expect:
             name.size() == length
          
             where:
             ignored = println ("where: \n p0=$p0\n p1=$p1")
             name << ["Kirk", "Spock", "Scotty"]
             length << [4, 5, 6]
           }
          }
          

          Now, this code does not get executed correctly when you try for the first time. It fails with the error:

          Test Failure: initializationError(HelloSpock)
          org.spockframework.runtime.InvalidSpeckError: Class 'HelloSpock' is not a Speck, or has not been compiled properly
          

          This is happening because before grab brings in spock-jar on the classpath, the scanning for AST transformations has already happened, so the class does not get a chance to undergo spock related AST transformations and when run, it is not recognized as a speck.

          2nd time onwards that issue is not there as the classpath has spock-jar now and the script correctly undergoes spock's AST transformation also and it is then run correctly as JUnit4 test.

          Since the AST transformation issue mention above is not related to the current JIRA, I want to commit the patch that makes the above script work(2nd time onwards) and mark this issue as fixed. Let me know if someone sees any issue with that.

          I will be interested in knowing views about the AST transformation issue and how it might be taken forward. Should scanning for AST transformation happen once more after GrabAnnotationTransformation has fetched stuff and updated the classpath?

          Show
          Roshan Dawrani added a comment - I tried a change with which the following script is working fine (but only from 2nd attempt onwards - details follow). import spock.lang.* @Grab(group='org.spockframework', module='spock-core', version='0.2') class HelloSpock extends Specification { def "can you figure out what I'm up to?" () { expect: name.size() == length where: ignored = println ( "where: \n p0=$p0\n p1=$p1" ) name << [ "Kirk" , "Spock" , "Scotty" ] length << [4, 5, 6] } } Now, this code does not get executed correctly when you try for the first time. It fails with the error: Test Failure: initializationError(HelloSpock) org.spockframework.runtime.InvalidSpeckError: Class 'HelloSpock' is not a Speck, or has not been compiled properly This is happening because before grab brings in spock-jar on the classpath, the scanning for AST transformations has already happened, so the class does not get a chance to undergo spock related AST transformations and when run, it is not recognized as a speck. 2nd time onwards that issue is not there as the classpath has spock-jar now and the script correctly undergoes spock's AST transformation also and it is then run correctly as JUnit4 test. Since the AST transformation issue mention above is not related to the current JIRA, I want to commit the patch that makes the above script work(2nd time onwards) and mark this issue as fixed. Let me know if someone sees any issue with that. I will be interested in knowing views about the AST transformation issue and how it might be taken forward. Should scanning for AST transformation happen once more after GrabAnnotationTransformation has fetched stuff and updated the classpath?
          Hide
          Roshan Dawrani added a comment -

          Still waiting for comments - for the confirmation that the issue that now remains has nothing to do with this JIRA (see previous comment for details) - before I go ahead and apply the patch.

          Show
          Roshan Dawrani added a comment - Still waiting for comments - for the confirmation that the issue that now remains has nothing to do with this JIRA (see previous comment for details) - before I go ahead and apply the patch.
          Hide
          blackdrag blackdrag added a comment -

          Roshan, I am not clear what your patch will do. As on the issue directly... If the grab annotation would be visited first in ResolveClass, including fetching the dependencies, then it would work I guess. But to me it becomes more and more clear that we should go with the following... make an annoation resolving try in conversion. And make the second, complete scan including failures normally in ResolveVisitor.

          Show
          blackdrag blackdrag added a comment - Roshan, I am not clear what your patch will do. As on the issue directly... If the grab annotation would be visited first in ResolveClass, including fetching the dependencies, then it would work I guess. But to me it becomes more and more clear that we should go with the following... make an annoation resolving try in conversion. And make the second, complete scan including failures normally in ResolveVisitor.
          Hide
          Roshan Dawrani added a comment -

          Attaching the patch here.

          GroovyShell checked whether a class was a JUnit4 test or a TestNG test with the correct class loader but then executed the tests using a different class loader (Class.forName()). That is why it was not seeing the JUnit4 classes that the GroovyShell loader was seeing after @grab added spock/junit4 URLs to it.

          The changes regarding the issue that will remain - possibly doing 2 scans to find transformations or some other approach - can be taken as an improvement/JIRA outside this one, right?

          Show
          Roshan Dawrani added a comment - Attaching the patch here. GroovyShell checked whether a class was a JUnit4 test or a TestNG test with the correct class loader but then executed the tests using a different class loader (Class.forName()). That is why it was not seeing the JUnit4 classes that the GroovyShell loader was seeing after @grab added spock/junit4 URLs to it. The changes regarding the issue that will remain - possibly doing 2 scans to find transformations or some other approach - can be taken as an improvement/JIRA outside this one, right?
          Hide
          Roshan Dawrani added a comment -

          Although spock here is junit4 based, even execution of TestNG tests by GroovyShell had the same issue, so I corrected that as well here itself.

          Show
          Roshan Dawrani added a comment - Although spock here is junit4 based, even execution of TestNG tests by GroovyShell had the same issue, so I corrected that as well here itself.
          Hide
          blackdrag blackdrag added a comment -

          the patch looks good to me. As for the transform recognition... yes, that should be an issue of its own

          Show
          blackdrag blackdrag added a comment - the patch looks good to me. As for the transform recognition... yes, that should be an issue of its own
          Hide
          Roshan Dawrani added a comment -

          Jochen, I tried adding a unit test case for the scenario reported here, but had to revert it because the @Grab download of groovy jar failed on the bamboo box for some reason. I removed the test case because it was a shaky one anyway and one that I was able to put in only for 1.6.x version and not for trunk for the following reason:

          • Apart from JUnit 4.7, spock-2.0 also was bringing in groovy-all-1.6.3 in the classpath. With trunk version, even locally I was getting java.lang.NoSuchMethodError: org.codehaus.groovy.ast.ModuleNode.getImport(Ljava/lang/String;)Lorg/codehaus/groovy/ast/ClassNode;, which, I guess, was because GCL was now seeing 2 different groovy versions on the classpath.

          I have locally tested it and I am fairly comfortable with it having tested it locally on 1.6.x and then you have seen it too.

          Let me know if you see any issue in me marking it "fixed".

          We can also wait for Peter to verify it from groovyconsole as reported in JIRA, if you want.

          Show
          Roshan Dawrani added a comment - Jochen, I tried adding a unit test case for the scenario reported here, but had to revert it because the @Grab download of groovy jar failed on the bamboo box for some reason. I removed the test case because it was a shaky one anyway and one that I was able to put in only for 1.6.x version and not for trunk for the following reason: Apart from JUnit 4.7, spock-2.0 also was bringing in groovy-all-1.6.3 in the classpath. With trunk version, even locally I was getting java.lang.NoSuchMethodError: org.codehaus.groovy.ast.ModuleNode.getImport(Ljava/lang/String;)Lorg/codehaus/groovy/ast/ClassNode;, which, I guess, was because GCL was now seeing 2 different groovy versions on the classpath. I have locally tested it and I am fairly comfortable with it having tested it locally on 1.6.x and then you have seen it too. Let me know if you see any issue in me marking it "fixed". We can also wait for Peter to verify it from groovyconsole as reported in JIRA, if you want.
          Hide
          Peter Niederwieser added a comment -

          I can confirm that HelloSpock now works from the second run onwards. The reason why you are getting NoSuchMethodError is that getImport() has changed incompatibly between Groovy 1.6 and 1.7. Spock 0.2 only works with Groovy 1.6.

          Show
          Peter Niederwieser added a comment - I can confirm that HelloSpock now works from the second run onwards. The reason why you are getting NoSuchMethodError is that getImport() has changed incompatibly between Groovy 1.6 and 1.7. Spock 0.2 only works with Groovy 1.6.
          Hide
          Roshan Dawrani added a comment -

          Thanks for confirming that, Peter.

          That incompatibility of getImport() is what I also meant to point to point out when I mentioned that after @Grab(bing) spock, groovy is seeing both 1.6 and 1.7 on its classpath and is running into that error.

          So, the plan is that we mark this JIRA as fixed as it has fixed the issue that was reported and then open another, linked JIRA to try to bring in some changes in AST transformation scanning so that this spock script can run from first attempt itself. Are you ok with that?

          Show
          Roshan Dawrani added a comment - Thanks for confirming that, Peter. That incompatibility of getImport() is what I also meant to point to point out when I mentioned that after @Grab(bing) spock, groovy is seeing both 1.6 and 1.7 on its classpath and is running into that error. So, the plan is that we mark this JIRA as fixed as it has fixed the issue that was reported and then open another, linked JIRA to try to bring in some changes in AST transformation scanning so that this spock script can run from first attempt itself. Are you ok with that?
          Hide
          Peter Niederwieser added a comment -

          Sure! Thanks for your work, Roshan.

          Show
          Peter Niederwieser added a comment - Sure! Thanks for your work, Roshan.
          Hide
          Roshan Dawrani added a comment -

          You're welcome, Peter.

          Show
          Roshan Dawrani added a comment - You're welcome, Peter.
          Hide
          Roshan Dawrani added a comment -

          Fixed.

          Show
          Roshan Dawrani added a comment - Fixed.
          Hide
          Roshan Dawrani added a comment -

          Hi Peter, I have fixed it in 1.6.6 now. Can you please try with the latest 1.6.6 snapshot and see if this spock script execution now works from groovyconsole - from the first run itself?

          Thanks.

          Show
          Roshan Dawrani added a comment - Hi Peter, I have fixed it in 1.6.6 now. Can you please try with the latest 1.6.6 snapshot and see if this spock script execution now works from groovyconsole - from the first run itself? Thanks.
          Hide
          Peter Niederwieser added a comment -

          Works fine now.

          Show
          Peter Niederwieser added a comment - Works fine now.

            People

            • Assignee:
              Roshan Dawrani
              Reporter:
              Peter Niederwieser
            • Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: