Skip to content

Commit 1029245

Browse files
committed
Create test to verify mongo beforeUpdate() changes are not persisted.
1 parent cebdaf0 commit 1029245

File tree

1 file changed

+194
-0
lines changed

1 file changed

+194
-0
lines changed
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* https://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.grails.datastore.gorm.mongo
20+
21+
import grails.persistence.Entity
22+
import org.apache.grails.data.mongo.core.GrailsDataMongoTckManager
23+
import org.apache.grails.data.testing.tck.base.GrailsDataTckSpec
24+
import org.bson.types.ObjectId
25+
import spock.lang.Issue
26+
27+
/**
28+
* Tests that properties set in beforeUpdate() are actually persisted to MongoDB.
29+
* This specifically tests the scenario where a property is set in beforeUpdate()
30+
* but was NOT explicitly modified by the user code.
31+
*/
32+
class BeforeUpdatePropertyPersistenceSpec extends GrailsDataTckSpec<GrailsDataMongoTckManager> {
33+
34+
void setupSpec() {
35+
manager.domainClasses.addAll([UserWithBeforeUpdate, UserWithBeforeUpdateAndAutoTimestamp])
36+
}
37+
38+
void "Test that properties set in beforeUpdate are persisted"() {
39+
given: "A user is created"
40+
def user = new UserWithBeforeUpdate(name: "Fred")
41+
def saved = user.save(flush: true)
42+
43+
expect: "The user was saved successfully"
44+
saved != null
45+
user.id != null
46+
user.errors.allErrors.size() == 0
47+
48+
when: "The session is cleared and user is retrieved"
49+
manager.session.clear()
50+
user = UserWithBeforeUpdate.get(user.id)
51+
52+
then: "beforeInsert was called and random was set"
53+
user != null
54+
user.name == "Fred"
55+
user.random == "Not Updated"
56+
57+
when: "The user's name is updated (but random is not explicitly modified)"
58+
def previousRandom = user.random
59+
user.name = "Bob"
60+
user.save(flush: true)
61+
manager.session.clear()
62+
user = UserWithBeforeUpdate.get(user.id)
63+
64+
then: "beforeUpdate was called and random was changed and persisted"
65+
user != null
66+
user.name == "Bob"
67+
user.random != previousRandom
68+
user.random != "Not Updated"
69+
user.random.length() == 5 // UUID substring [0..4]
70+
}
71+
72+
void "Test that beforeUpdate is called even when no properties are explicitly modified"() {
73+
given: "A user is created"
74+
def user = new UserWithBeforeUpdate(name: "Fred")
75+
user.save(flush: true)
76+
manager.session.clear()
77+
user = UserWithBeforeUpdate.get(user.id)
78+
def previousRandom = user.random
79+
80+
when: "The user is saved without any explicit property changes"
81+
user.save(flush: true)
82+
manager.session.clear()
83+
user = UserWithBeforeUpdate.get(user.id)
84+
85+
then: "beforeUpdate was called and random was updated"
86+
user != null
87+
user.random != previousRandom
88+
user.random != "Not Updated"
89+
user.random.length() == 5
90+
}
91+
92+
void "Test that multiple updates continue to trigger beforeUpdate"() {
93+
given: "A user is created"
94+
def user = new UserWithBeforeUpdate(name: "Fred")
95+
user.save(flush: true)
96+
manager.session.clear()
97+
98+
when: "The user is updated multiple times"
99+
def randomValues = []
100+
3.times {
101+
user = UserWithBeforeUpdate.get(user.id)
102+
randomValues << user.random
103+
user.name = "Name${it}"
104+
user.save(flush: true)
105+
manager.session.clear()
106+
}
107+
user = UserWithBeforeUpdate.get(user.id)
108+
109+
then: "Each update generated a new random value"
110+
randomValues.size() == 3
111+
randomValues[0] == "Not Updated" // from beforeInsert
112+
randomValues[1] != "Not Updated" // first update
113+
randomValues[2] != randomValues[1] // second update
114+
user.random != randomValues[2] // third update
115+
user.random.length() == 5
116+
}
117+
118+
@Issue('GPMONGODB-XXX')
119+
void "Test that properties set in beforeUpdate with AutoTimestamp are persisted"() {
120+
given: "A user with auto timestamp is created"
121+
def user = new UserWithBeforeUpdateAndAutoTimestamp(name: "Fred")
122+
user.save(flush: true)
123+
manager.session.clear()
124+
125+
when: "The user is retrieved"
126+
user = UserWithBeforeUpdateAndAutoTimestamp.get(user.id)
127+
128+
then: "beforeInsert was called and random was set"
129+
user != null
130+
user.name == "Fred"
131+
user.random == "Not Updated"
132+
user.dateCreated != null
133+
user.lastUpdated != null
134+
135+
when: "The user's name is updated"
136+
sleep 100 // ensure lastUpdated differs
137+
def previousRandom = user.random
138+
def previousLastUpdated = user.lastUpdated
139+
user.name = "Bob"
140+
user.save(flush: true)
141+
manager.session.clear()
142+
user = UserWithBeforeUpdateAndAutoTimestamp.get(user.id)
143+
144+
then: "beforeUpdate was called, random was changed, and lastUpdated was updated"
145+
user != null
146+
user.name == "Bob"
147+
user.random != previousRandom
148+
user.random != "Not Updated"
149+
user.random.length() == 5
150+
user.lastUpdated > previousLastUpdated
151+
}
152+
}
153+
154+
@Entity
155+
class UserWithBeforeUpdate {
156+
157+
ObjectId id
158+
String name
159+
String random
160+
161+
static constraints = {
162+
random nullable: true
163+
}
164+
165+
def beforeInsert() {
166+
random = "Not Updated"
167+
}
168+
169+
def beforeUpdate() {
170+
random = UUID.randomUUID().toString()[0..4]
171+
}
172+
}
173+
174+
@Entity
175+
class UserWithBeforeUpdateAndAutoTimestamp {
176+
177+
ObjectId id
178+
String name
179+
String random
180+
Date dateCreated
181+
Date lastUpdated
182+
183+
static constraints = {
184+
random nullable: true
185+
}
186+
187+
def beforeInsert() {
188+
random = "Not Updated"
189+
}
190+
191+
def beforeUpdate() {
192+
random = UUID.randomUUID().toString()[0..4]
193+
}
194+
}

0 commit comments

Comments
 (0)