Using Groovy Trait in Grails Test Fails
Asked Answered
C

2

6

How can I implement Groovy's new traits in my Grails Spock tests? Every time I try, I get a stacktrace that looks like this. Is there some limitation of Groovy trails that I might not be aware of?

JDK Version:

java version "1.7.0_65"
OpenJDK Runtime Environment (IcedTea 2.5.3) (7u71-2.5.3-0ubuntu0.14.04.1)
OpenJDK 64-Bit Server VM (build 24.65-b04, mixed mode)

Groovy Verison:

Groovy Version: 2.3.6 JVM: 1.7.0_65 Vendor: Oracle Corporation OS: Linux

Grails Version:

Grails version: 2.4.3

Simplified Code:

import grails.test.mixin.Mock
@Mock([AnalyticFilters])
trait ControllerTestBase {
public void setupCommonStuff(boolean setupIdCall = false) {
params.devId = TEST_DEV_ID
    // mocking version filter
    params.version = "v${TEST_VERSION}"

    defineBeans{
       CacheService(cacheServiceMock: "createMock")
    }

    CommonParams.parseParams(params)

    cacheMock = applicationContext.getBean("cacheServiceMock")

    if(setupStoreIdCall) {
        cacheMock.demandExplicit.makeCompositeKey(0..20) { List<String> list ->
            def (String uuid, String orgUuid) = list
            return "foobar"
        }
    }

}
}

@TestFor(AuditController)
public class AuditControllerSpecs extends Specification implements ControllerTestBase {

private def auditServiceFactory

public String testAuditData = "{audit:'whatever'}"

public void setup() {
    setupCommonParams()

    defineBeans {
        auditServiceFactory(GrailsMock, AuditService)
        auditService(auditServiceFactory: "createMock")
    }
    auditServiceFactory = applicationContext.getBean("auditServiceFactory")
    auditServiceFactory.demand.writeEventToMongo { BasicDBObject data -> }
    controller.auditService = applicationContext.getBean('auditService', AuditService)
}

def "calling productAudit should return with 200 and OK"() {

    given:
    request.JSON = JSON.parse(testAuditData)
    request.method = 'POST'
    when:
    withFilters(action: "productAudit") {
        controller.productAudit()
    }
    then:

    def res = JSON.parse(response.text)

    expect:
    response.status == 200
    res.message == "OK"
    100 == 2
}

}

Stacktrace:

 [groovyc] org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
  [groovyc] General error during canonicalization: Comparison method violates its general contract!
  [groovyc] 
  [groovyc] java.lang.IllegalArgumentException: Comparison method violates its general contract!
  [groovyc]     at java.util.TimSort.mergeLo(TimSort.java:747)
  [groovyc]     at java.util.TimSort.mergeAt(TimSort.java:483)
  [groovyc]     at java.util.TimSort.mergeCollapse(TimSort.java:410)
  [groovyc]     at java.util.TimSort.sort(TimSort.java:214)
  [groovyc]     at java.util.TimSort.sort(TimSort.java:173)
  [groovyc]     at java.util.Arrays.sort(Arrays.java:659)
  [groovyc]     at java.util.Collections.sort(Collections.java:217)
  [groovyc]     at org.codehaus.groovy.transform.trait.TraitComposer.applyTrait(TraitComposer.java:183)
  [groovyc]     at org.codehaus.groovy.transform.trait.TraitComposer.doExtendTraits(TraitComposer.java:105)
  [groovyc]     at org.codehaus.groovy.control.CompilationUnit$4.call(CompilationUnit.java:188)
  [groovyc]     at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1047)
  [groovyc]     at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:583)
  [groovyc]     at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:561)
  [groovyc]     at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:538)
  [groovyc]     at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:517)
  [groovyc]     at org.codehaus.groovy.tools.FileSystemCompiler.compile(FileSystemCompiler.java:59)
  [groovyc]     at org.codehaus.groovy.tools.FileSystemCompiler.doCompilation(FileSystemCompiler.java:215)
  [groovyc]     at org.codehaus.groovy.ant.Groovyc.runCompiler(Groovyc.java:1104)
  [groovyc]     at org.codehaus.groovy.ant.Groovyc.compile(Groovyc.java:1155)
  [groovyc]     at org.codehaus.groovy.grails.compiler.Grailsc.compile(Grailsc.java:78)
  [groovyc]     at org.codehaus.groovy.ant.Groovyc.execute(Groovyc.java:770)
  [groovyc]     at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
  [groovyc]     at sun.reflect.GeneratedMethodAccessor51.invoke(Unknown Source)
  [groovyc]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  [groovyc]     at java.lang.reflect.Method.invoke(Method.java:606)
  [groovyc]     at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
  [groovyc]     at groovy.util.AntBuilder.performTask(AntBuilder.java:319)
  [groovyc]     at groovy.util.AntBuilder.nodeCompleted(AntBuilder.java:264)
  [groovyc]     at groovy.util.BuilderSupport.doInvokeMethod(BuilderSupport.java:147)
  [groovyc]     at groovy.util.AntBuilder.doInvokeMethod(AntBuilder.java:203)
  [groovyc]     at groovy.util.BuilderSupport.invokeMethod(BuilderSupport.java:64)
Caspian answered 2/12, 2014 at 21:48 Comment(2)
Depends on how it is being used. can you add what are you up to?Hadsall
Can you tell me which JVM version you use?Nitride
S
9

The same exception occurs in our project which makes heavy use of traits:

java.lang.IllegalArgumentException: Comparison method violates its general contract!

My colleague found out that this happens as soon as a trait has more than 10 fields. The origin of this behavior is unknown to us.

As a workaround we make use of trait inheritance:

trait Foo extends MoreFoo {
    //this has 10 fields
}

trait MoreFoo{
    //this has some more fields but not more than 10
}

It is noteworthy that we use Groovy on Android so adjusting JVM options as proposed by ColimMc is not an option.

Squinty answered 2/6, 2015 at 12:41 Comment(3)
had the problem with 10 fields in trait, removed one and all was normal again, interesting thing is all was ok until i restarted computerSparing
Just hit the exact same ambiguous compiler error with a trait with 10+ fields - lowering the number to <10 solved it - what a strange error (groovy-eclipse compiler 2.9.2-01, groovy-all 2.4.9.Yezd
@TomBunting I am glad that you found this issue and did not waste more time on it. This is indeed a strange error, it is extremely difficult to locate when working with traits.Squinty
M
-1

It seems to me that there is a limit with script fields that use traits. If the number of fields from the implementation that is using a trait reaches a certain size (my case 34 methods) then this exception gets thrown. I'm currently running into this same issue that you have and I'm trying to solve it.

I was able to get around Groovy by using:

-Djava.util.Arrays.useLegacyMergeSort=true

as mentioned here: https://mcmap.net/q/49850/-quot-comparison-method-violates-its-general-contract-quot-timsort-and-gridlayout

I think it has to do with their GETTER_FIRST_COMPARATOR comparator where it doesn't return 0. It only returns 1 and -1 which I think is the reason why it mentions a contract violation.

Matthias answered 21/4, 2015 at 11:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.