I have A simple Customer + PaswordReset datamodel.
In my PasswordService I call PasswordReset.findByUsername() and save() and it works fine.
I then made PasswordServiceTests which has @Mock([Customer, PasswordReset]) In that test I create a new Customer object and use Customer.save and use PasswordReset.findByUsername(). Both work fine.
The test call service.initatePasswordReset() (PasswordService) which uses both Customer.findByUsername() and PasswordReset.save() successfully.
In the test I then call PasswordReset.findByUsername(...) and find the object made by the service.initiateReset().
But when I call another method: service.performReset(), which successfully loads the customer object by using Customer.findByUsername(..), modifies the customer password field and tries to do customer.save()
The following error is caused by the customer.save() in the PasswordService. Can anyone tell me what is wrong?
java.lang.IndexOutOfBoundsException: Index: 1, Size: 1 at java.util.ArrayList.rangeCheck(ArrayList.java:604) at java.util.ArrayList.remove(ArrayList.java:445) at org.grails.datastore.mapping.simple.engine.SimpleMapEntityPersister$1.deindex(SimpleMapEntityPersister.groovy:101) at org.grails.datastore.mapping.engine.NativeEntryEntityPersister.updatePropertyIndices(NativeEntryEntityPersister.java:1200) at org.grails.datastore.mapping.engine.NativeEntryEntityPersister.access$100(NativeEntryEntityPersister.java:55) at org.grails.datastore.mapping.engine.NativeEntryEntityPersister$4.run(NativeEntryEntityPersister.java:958) at org.grails.datastore.mapping.core.impl.PendingOperationExecution.executePendingOperation(PendingOperationExecution.java:36) at org.grails.datastore.mapping.core.AbstractSession.flushPendingOperations(AbstractSession.java:323) at org.grails.datastore.mapping.core.AbstractSession.flushPendingUpdates(AbstractSession.java:302) at org.grails.datastore.mapping.core.AbstractSession.flush(AbstractSession.java:240) at org.grails.datastore.gorm.GormInstanceApi.doSave(GormInstanceApi.groovy:168) at org.grails.datastore.gorm.GormInstanceApi$_save_closure4.doCall(GormInstanceApi.groovy:143) at org.grails.datastore.mapping.core.DatastoreUtils.execute(DatastoreUtils.java:301) at org.grails.datastore.gorm.AbstractDatastoreApi.execute(AbstractDatastoreApi.groovy:34) at org.grails.datastore.gorm.GormInstanceApi.save(GormInstanceApi.groovy:142) at com.foo.services.PasswordService.performPasswordReset(PasswordService.groovy:33) at com.foo.services.PasswordServiceTests.testResetPassword(PasswordServiceTests.groovy:47)
PasswordServiceTest.groovy
@TestFor(PasswordService)
@Mock([Customer, PasswordReset])
class PasswordServiceTests {
void setUp() {
mockCodec(MD5Codec)
// mockService(CustomerRegistrationService)
}
void testResetPassword() {
Customer c = CustomerRegistrationServiceTests.makePrivateCustomer()
c.sumUnpaidInvoices = 0
c.sumOverdueInvoices = 0
c.password = service.hashPassword(c)
c.customerType = CustomerType.NormalCustomer.value
c.save(flush: true);
assertEquals("Mock DB does not contain 1 customer", 1, Customer.list().size())
service.initiatePasswordReset(c.username)
def pwReset = PasswordReset.findByUsername(c.username)
println("psreset saved: " + pwReset.username + " / " + pwReset.code)
assertEquals(c.username, pwReset.username)
service.performPasswordReset(c.username, "test"); // CALLS METHOD BELOW
}
}
Method in PasswordService.groovy:
def performPasswordReset(String username, String newPassword) {
Customer customer = Customer.findByUsername(username)
if(customer != null) {
customer.password = newPassword;
customer.password = hashPassword(customer);
customer.save(flush: true); // CAUSES THE ERROR
....
}
}
I fixed this problem by removing the call to customer.save() in the service, it was not required and even without customer.save the password is still stored to database automatically when you change it (customer.password = "foo").