Grails 2.4 upgrade issues from 2.2 test event called at app startup - grails

At application startup the eventTestPhasesStart event code in _events script is being called. The test classes referenced in the event code are not available when executing runapp which leads to classes not resolved errors at startup.
unable to resolve class org.codehaus.groovy.grails.test.spock.GrailsSpecTestType
unable to resolve class - org.codehaus.groovy.grails.test.junit4.JUnit4GrailsTestType
unable to resolve class org.codehaus.groovy.grails.test.runner.phase.IntegrationTestPhaseConfigurer
This code also fails to run in forked mode which has forced us to turn forked mode off to run the integration tests which means we cannot use the debugger to debug tests as Grails 2.4 now requires.
The following is the event code:
eventTestPhasesStart = {phasesToRun ->
println "setting inmem phase"
phasesToRun << "inmem"
def inmemPhaseConfigurer = new IntegrationTestPhaseConfigurer(projectTestRunner.projectTestCompiler, projectLoader)
projectTestRunner.testFeatureDiscovery.configurers.inmem = inmemPhaseConfigurer
def inmemtestTypeName = "inmem"
def inmemtestDirectory = "inmem"
def inmemtestMode = new GrailsTestMode(autowire: true, wrapInTransaction: true, wrapInRequestEnvironment: true)
inmemTestTypes = []
inmemTestTypes << (new GrailsSpecTestType(inmemtestTypeName+"Spock", inmemtestDirectory, inmemtestMode))
inmemTestTypes << (new JUnit4GrailsTestType(inmemtestTypeName+"JUnit", inmemtestDirectory, inmemtestMode))
projectTestRunner.testFeatureDiscovery.testExecutionContext.inmemTests = inmemTestTypes
}
When running in forked mode this event is again called when/where it shouldn't resulting in the dynamic properties such as projectTestRunner not being found.
Is there a way to prevent this script from being executed when it shouldn't?
thank you

Related

Grails spock service test not calling service method

I'm seeing some strange behavior in a spock test for a service using Grails 2.3.7.
This test works fine:
void "create spot order"() {
given:
def createOrderCommand = newCreateOrderCommand(OrderType.S)
when:
def orderId = service.createOrder(createOrderCommand, user).id.toInteger()
then:
Order.count() == 1
when:
def order = service.orderById(orderId)
then:
// a bunch of assertions
}
This test also works fine:
void "create command with invalid order id"() {
when:
service.commandForOrderId(999)
then:
def exception = thrown(CreateOrderException)
exception.key == "orderService.invalid.order.id"
}
However this test fails - I've set a breakpoint at the beginning commandForOrderId, and it is never hit. command is null (this is where the test fails, on the line checking for null on command), which would never be returned from this service method:
void "create spot command"() {
given:
def createOrderCommand = newCreateOrderCommand(OrderType.S)
when:
def order = service.createOrder(createOrderCommand, user)
then:
Order.count() == 1
when:
def orderId = order.id.toInteger()
def command = service.commandForOrderId(orderId)
then:
command
// a bunch more assertions
}
I've tried removing the #Transactional annotation from the service, using the transactional static field, as well as using neither of these. I've also tried changing the service method to a closure, all with no luck.
I changed the service method to a closure, cleared my target directories, did every manner of clean I know of (within GGTS and grails commands), and the service method started getting hit in the test. I'm still unsure of the actual cause of this error, however.

Grails: importing plugin classes to _Events.groovy

I've created a Grails plugin which adds a custom test type class (extending GrailsTestTypeSupport) and custom test result class (extending GrailsTestTypeResult) to support a custom test type that I run during the other phase of the test-app script. Testing this on my local machine has gone swimmingly but...
When I packaged the plugin to use in my app, the tests are blowing up on our CI server (Jenkins). Here's the error that Jenkins is spitting out:
unable to resolve class CustomTestResult # line 58, column 9.
new CustomTestResult(tests.size() - failed, failed)
It appears that I cannot simply import these classes into _Events.groovy, and the classes are not otherwise on the classpath. But I'll be damned if I can figure out how to get them onto the classpath. Here's what I have so far (in _Events.groovy):
import java.lang.reflect.Constructor
eventAllTestsStart = {
if (!otherTests) otherTests = []
loadCustomTestResult()
otherTests << createCustomTestType()
}
private def createCustomTestType(String name = 'js', String relativeSourcePath = 'js') {
ClassLoader parent = getClass().getClassLoader()
GroovyClassLoader loader = new GroovyClassLoader(parent)
Class customTestTypeClass = loader.parseClass(new File("${customTestPluginDir}/src/groovy/custom/test/CustomTestType.groovy"))
Constructor customTestTypeConstructor = customTestTypeClass.getConstructor(String, String)
def customTestType = customTestTypeConstructor.newInstance(name, relativeSourcePath)
customTestType
}
private def loadCustomTestResult() {
ClassLoader parent = getClass().getClassLoader()
GroovyClassLoader loader = new GroovyClassLoader(parent)
Class customTestResultClass = loader.parseClass(new File("${customTestPluginDir}/src/groovy/custom/test/CustomTestResult.groovy"))
}
Currently: CustomTestResult is only referenced from within CustomTestType. As far as I can tell, _Events.groovy is loading CustomTestType but it is failing because it then insists that CustomTestResult is not on the classpath.
Putting aside for a moment that it seems crazy that there's this much overhead to get plugin-furnished classes onto the classpath for the test cycle to begin with... I'm not quite sure where I've gotten tripped up. Any help or pointers would be greatly appreciated.
Have you tried simply loading the class in question via the ClassLoader that is accessible via the classLoader variable in _Events.groovy?
Class customTestTypeClass = classLoader.loadClass('custom.test.CustomTestType')
// use nice groovy overloading of Class.newInstance
return customTestTypeClass.newInstance(name, relativeSourcePath)
You should be late enough in the process at eventAllTestsStart for this to be valid.
#Ian Roberts' answer got me pointed in roughly the right direction, and combined with the _Events.groovy script from this grails-cucumber plugin, I managed to come through with this solution:
First, _Events.groovy became this:
eventAllTestsStart = { if (!otherTests) otherTests = [] }
eventTestPhasesStart = { phases ->
if (!phases.contains('other')) { return }
// classLoader.loadClass business per Ian Roberts:
otherTests << classLoader.loadClass('custom.test.CustomTestType').newInstance('js', 'js')
}
Which is far more readable than where I was at the start of this thread. But: I was in roughly the same position: my ClassNotFoundException moved from being thrown in _Events.groovy to being thrown from within CustomTestType when it tried to create an instance of custom.test. CustomTestResult. So within CustomTestType, I added the following method:
private GrailsTestTypeResult createResult(passed, failed) {
try {
return new customTestResult(passed, failed)
} catch(ClassNotFoundException cnf) {
Class customTestResult = buildBinding.classLoader.loadClass('custom.test.CustomTestResult')
return customTestResult.newInstance(passed, failed)
}
}
So Ian was right, inasmuch as classLoader came to the rescue -- I just wound up needing its magic in two places.

TestDataConfig.groovy not found, build-test-data plugin proceeding without config file

I am getting the following error when including in Mixin Build in unit tests:
TestDataConfig.groovy not found, build-test-data plugin proceeding without config file
it works like charm in the integration tests but not part of unit tests. I mean, 'build' plugin works itself in unit test but the 'TestDataConfig' is not populating default values
Thank You
First you should verify the version from build-test-data in your BuildConfig.groovy
test ":build-test-data:2.0.3"
Second, check your test. If you want build objects you need:
import grails.buildtestdata.mixin.Build
...
#TestFor(TestingClass)
#Build([TestingClass, SupportClass, AnotherClass])
class TestingClassTest{
#Test
void testMethod{
def tc1 = TestingClass.build()
def sc1 = SuportClass.build()
def ac1 = AnotherClass.build()
}
}
Third, check the domains constraints, you could have some properties validations like unique that fails when you build two instances. You need set that properties in code:
def tc1 = TestingClass.build(uniqueProperty: 'unique')
def tc2 = TestingClass.build(uniqueProperty: 'special')
I guess the dependency should be:
test ":build-test-data:2.0.3"
Since is just used for testing, right?

Automatically Reload Template Files

I have a pretty standard 2.0.3 Grails app and I've executed grails install-templates which places files list.gsp, edit.gsp, etc. in src/templates/scaffolding/ directory. These files are not automatically reloaded when a change is made to them. Is there a way I can get these to be automatically reloaded so I don't have to stop/start the app every time I make a change? I've tried looking at watchedResources but that seems to be plugin development related.
You are correct that the "watched-resources" mechanism only applies to plugins. The correct fix for this would be to modify the core ScaffoldingGrailsPlugin.groovy to add
def watchedResources = "file:./src/templates/scaffolding/*"
and it's probably worth submitting a JIRA to that effect. In the mean time, you may be able to get it working by writing a simple plugin of your own to "inject" this behaviour into the scaffolding plugin. Do grails create-plugin watch-scaffolding and then use the following for the plugin descriptor:
import org.codehaus.groovy.grails.plugins.GrailsPlugin
class WatchScaffoldingGrailsPlugin {
def version = "0.1"
def grailsVersion = "2.0 > *"
def dependsOn = [:]
def pluginExcludes = [ "grails-app/views/error.gsp" ]
def title = "Watch Scaffolding Plugin"
def author = "Your name"
def authorEmail = ""
def description = '''\
Watches for changes to scaffolding templates and reloads dynamically-scaffolded
controllers and views.
'''
// URL to the plugin's documentation
def documentation = "http://grails.org/plugin/watch-scaffolding"
// watch for changes to scaffolding templates...
def watchedResources = "file:./src/templates/scaffolding/*"
// ... and kick the scaffolding plugin when they change
def onChange = { event ->
event.manager.getGrailsPlugin('scaffolding').notifyOfEvent(
GrailsPlugin.EVENT_ON_CHANGE, null)
}
// rest of plugin options are no-op
def onConfigChange = { event -> }
def doWithWebDescriptor = { xml -> }
def doWithSpring = { }
def doWithDynamicMethods = { ctx -> }
def doWithApplicationContext = { applicationContext -> }
def onShutdown = { event -> }
}
Now in your application's BuildConfig.groovy add
grails.plugin.location.'watch-scaffolding' = '../watch-scaffolding'
(or whatever is the appropriate relative path from the root of your app to the root of the plugin) and your scaffolding template changes should start to reload automatically.
(This is tested on Grails 2.1, I initially tried using influences but it didn't have any effect, however forcing an onChange event in the scaffolding plugin had the required result.)
This code flushes scaffolding cache. You can create a specific admin action for it:
org.codehaus.groovy.grails.scaffolding.view.
ScaffoldingViewResolver.scaffoldedViews.clear()
According to GRAILS-755, this has been fixed, but I don't think it has because they don't reload for me either.
From that Jira, here is a possible workaround:
Use the console plugin, and run this command to clear the dynamic
scaffolded view cache:
​def scaffoldedView =
org.codehaus.groovy.grails.scaffolding.view.ScaffoldingViewResolver.scaffoldedViews.clear()​
After that, the next time I request a page, it doesn't find it in the
cache, and thus goes back to the disk to recreate it.

Integration Tests started to fail with grails upgrade

I upgraded a grails app from 1.2.2 to 1.3.7 after this upgrade a few integration tests have started to throw the following error the 'validateAndSaveList' is a method on a service used by the service I'm testing. These tests were passing before the upgrade and they will also pass if I run just the integration test phase with grails test-app -integration
junit.framework.AssertionFailedError:
No more calls to 'validateAndSaveList'
expected at this point. End of
demands.
Code:
import com.e.domain.*
import com.e.exception.GORMServiceException
import com.e.controller.SecurityUserCommand
class AccountServiceTests extends GroovyTestCase
{
def accountService
void testRegisterWithMinimumInfo()
{
def clinic = new Clinic(name:'clinicName')
def securityUserCommand = new SecurityUserCommand(username:'username', password:"password", confirm:"password")
def clinicUser = new ClinicUser(firstName:'fname', lastName:'lname', emailAddress:'abc#abc.com')
clinicUser.clinic = clinic
//clinicUser.securityUser = securityUser
clinic.address = new Address()
// TODO - JsecUser no longer in use
def role = new ShiroRole(name:'TEST')
//def subscription = ESubscription.findByName('Charter Member')
def subscription = new ESubscription(
name:'Charter Member',
description:'Charter Member',
periodType:'Monthly',
numPeriods:12,
amountPerPeriod:25.00,
electronicSubmissionRate:0.00,
accountingRate:0.01,
numAllowedUsers:4,
startDate: today -1,
endDate: today+1
)
subscription.save(flush:true)
if(subscription.hasErrors())
println subscription.errors
assertNotNull subscription
clinicUser.empathicCustomerProfile.subscription = subscription
def result = accountService.register(clinic, securityUserCommand, clinicUser, role)
assert result.success
assert result.clinic.id
assert result.securityUser?.id
assert result.clinicUser.id
}
StackTrace
junit.framework.AssertionFailedError: No more calls to 'validateAndSaveList' expected at this point. End of demands.
at grails.test.MockClosureProxy.doBeforeCall(MockClosureProxy.java:66)
at grails.test.AbstractClosureProxy.call(AbstractClosureProxy.java:74)
at grails.test.GrailsMock$_createMock_closure1.doCall(GrailsMock.groovy:125)
at com.e.service.AccountService.register(AccountService.groovy:46)
at com.e.service.AccountService$register.call(Unknown Source)
at AccountServiceTests.testRegisterWithMinimumInfo(AccountServiceTests.groovy:53)
this answer comes from working the issue out in the comments:
the exception you are getting clearly indicates that somewhere you have put a mock object in your service, and the service is calling the mock object in a way it was not set up to handle.
The root problem as seen from #hvgotcodes is that there was a mock object for the service even though in that given test there was no mocking happening.
This happened in grails 1.3.7
I found a unit test that was doing the following:
def dataBindServiceControl = mockFor(DataBindService)
dataBindServiceControl.demand.safeBind{}
dataBindServiceControl.demand.extractPhones{}
dataBindServiceControl.demand.validateAndSaveList{l-> return true}
def dataBindService = dataBindServiceControl.createMock()
controller.dataBindService = dataBindService
If those tests were removed then all the integration tests would pass so to solve with out rewriting the tests I added the following to the tear down method.
GroovySystem.metaClassRegistry.removeMetaClass(DataBindService)
With this addition the tests are now working correctly in grails 1.3.7

Resources