/tests/com/google/appengine/datanucleus/jdo/JDOConcurrentModificationTest.java

http://datanucleus-appengine.googlecode.com/ · Java · 485 lines · 391 code · 46 blank · 48 comment · 10 complexity · 9f4ff023848d89da426de04cbfa6f7eb MD5 · raw file

  1. /*
  2. * /**********************************************************************
  3. * Copyright (c) 2009 Google Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. * **********************************************************************/
  17. package com.google.appengine.datanucleus.jdo;
  18. import com.google.appengine.api.datastore.Entity;
  19. import com.google.appengine.datanucleus.CollisionDatastoreDelegate;
  20. import com.google.appengine.datanucleus.ExceptionThrowingDatastoreDelegate;
  21. import com.google.appengine.datanucleus.Inner;
  22. import com.google.appengine.datanucleus.test.jdo.Flight;
  23. import java.util.ConcurrentModificationException;
  24. import javax.jdo.JDODataStoreException;
  25. import org.datanucleus.exceptions.NucleusDataStoreException;
  26. /**
  27. * @author Max Ross <maxr@google.com>
  28. */
  29. @Inner
  30. public class JDOConcurrentModificationTest extends JDOTestCase {
  31. public void testInsertCollides() {
  32. CollisionDatastoreDelegate dd = new CollisionDatastoreDelegate(getDelegateForThread());
  33. setDelegateForThread(dd);
  34. try {
  35. Flight flight = new Flight();
  36. flight.setName("harold");
  37. flight.setOrigin("bos");
  38. flight.setDest("mia");
  39. flight.setYou(23);
  40. flight.setMe(24);
  41. flight.setFlightNumber(88);
  42. beginTxn();
  43. try {
  44. pm.makePersistent(flight);
  45. fail("expected exception");
  46. } catch (JDODataStoreException e) {
  47. // good
  48. assertTrue(e.getCause() instanceof ConcurrentModificationException);
  49. }
  50. assertTrue(pm.currentTransaction().isActive());
  51. rollbackTxn();
  52. assertEquals(flight, "harold", "bos", "mia", 23, 24, 88);
  53. } finally {
  54. setDelegateForThread(dd.getInner());
  55. }
  56. }
  57. public void testInsertCollidesOnCommit() {
  58. ExceptionThrowingDatastoreDelegate.ExceptionPolicy policy =
  59. new ExceptionThrowingDatastoreDelegate.BaseExceptionPolicy() {
  60. int count = 0;
  61. protected void doIntercept(String methodName) {
  62. if (count != 0) {
  63. throw new ConcurrentModificationException();
  64. }
  65. count++;
  66. }
  67. };
  68. ExceptionThrowingDatastoreDelegate dd =
  69. new ExceptionThrowingDatastoreDelegate(getDelegateForThread(), policy);
  70. setDelegateForThread(dd);
  71. try {
  72. Flight flight = new Flight();
  73. flight.setName("harold");
  74. flight.setOrigin("bos");
  75. flight.setDest("mia");
  76. flight.setYou(23);
  77. flight.setMe(24);
  78. flight.setFlightNumber(88);
  79. beginTxn();
  80. pm.makePersistent(flight);
  81. try {
  82. commitTxn();
  83. fail("expected exception");
  84. } catch (JDODataStoreException e) {
  85. // good
  86. assertTrue(e.getCause() instanceof ConcurrentModificationException);
  87. }
  88. assertFalse(pm.currentTransaction().isActive());
  89. assertEquals(flight, "harold", "bos", "mia", 23, 24, 88);
  90. } finally {
  91. setDelegateForThread(dd.getInner());
  92. }
  93. }
  94. public void testUpdateCollides() {
  95. Entity e = Flight.newFlightEntity("harold", "bos", "mia", 23, 24, 88);
  96. ds.put(e);
  97. CollisionDatastoreDelegate dd = new CollisionDatastoreDelegate(getDelegateForThread());
  98. setDelegateForThread(dd);
  99. try {
  100. beginTxn();
  101. Flight f = pm.getObjectById(Flight.class, e.getKey());
  102. f.setYou(12);
  103. try {
  104. commitTxn();
  105. fail("expected exception");
  106. } catch (JDODataStoreException ex) {
  107. // good
  108. assertTrue(ex.getCause() instanceof ConcurrentModificationException);
  109. }
  110. assertFalse(pm.currentTransaction().isActive());
  111. } finally {
  112. setDelegateForThread(dd.getInner());
  113. }
  114. }
  115. public void testUpdateOfDetachedCollides() {
  116. Entity e = Flight.newFlightEntity("harold", "bos", "mia", 23, 24, 88);
  117. ds.put(e);
  118. beginTxn();
  119. Flight f = pm.detachCopy(pm.getObjectById(Flight.class, e.getKey()));
  120. commitTxn();
  121. CollisionDatastoreDelegate dd = new CollisionDatastoreDelegate(getDelegateForThread());
  122. setDelegateForThread(dd);
  123. try {
  124. // update detached object
  125. f.setYou(12);
  126. beginTxn();
  127. // reattach
  128. pm.makePersistent(f);
  129. try {
  130. commitTxn();
  131. fail("expected exception");
  132. } catch (JDODataStoreException ex) {
  133. // good
  134. assertTrue(ex.getCause() instanceof ConcurrentModificationException);
  135. }
  136. assertFalse(pm.currentTransaction().isActive());
  137. // now verify that the new value is still in the detached version.
  138. assertEquals(f, "harold", "bos", "mia", 12, 24, 88);
  139. } finally {
  140. setDelegateForThread(dd.getInner());
  141. }
  142. }
  143. public void testUpdateOfDetachedCollidesThenSucceeds() {
  144. ExceptionThrowingDatastoreDelegate.ExceptionPolicy policy =
  145. new ExceptionThrowingDatastoreDelegate.BaseExceptionPolicy() {
  146. int count = 0;
  147. protected void doIntercept(String methodName) {
  148. if (count == 0) {
  149. count++;
  150. throw new ConcurrentModificationException();
  151. }
  152. }
  153. };
  154. Entity e = Flight.newFlightEntity("harold", "bos", "mia", 23, 24, 88);
  155. ds.put(e);
  156. beginTxn();
  157. Flight f = pm.detachCopy(pm.getObjectById(Flight.class, e.getKey()));
  158. commitTxn();
  159. ExceptionThrowingDatastoreDelegate dd =
  160. new ExceptionThrowingDatastoreDelegate(getDelegateForThread(), policy);
  161. setDelegateForThread(dd);
  162. try {
  163. // update detached object
  164. f.setYou(12);
  165. beginTxn();
  166. // reattach
  167. pm.makePersistent(f);
  168. try {
  169. commitTxn();
  170. fail("expected exception");
  171. } catch (JDODataStoreException ex) {
  172. // good
  173. assertTrue(ex.getCause() instanceof ConcurrentModificationException);
  174. }
  175. assertFalse(pm.currentTransaction().isActive());
  176. beginTxn();
  177. pm.makePersistent(f);
  178. commitTxn();
  179. beginTxn();
  180. f = pm.getObjectById(Flight.class, e.getKey());
  181. assertEquals(f, "harold", "bos", "mia", 12, 24, 88);
  182. commitTxn();
  183. } finally {
  184. setDelegateForThread(dd.getInner());
  185. }
  186. }
  187. public void testUpdateOfAttachedCollidesThenSucceeds() {
  188. ExceptionThrowingDatastoreDelegate.ExceptionPolicy policy =
  189. new ExceptionThrowingDatastoreDelegate.BaseExceptionPolicy() {
  190. int count = 0;
  191. protected void doIntercept(String methodName) {
  192. if (count == 0) {
  193. count++;
  194. throw new ConcurrentModificationException();
  195. }
  196. }
  197. };
  198. Entity e = Flight.newFlightEntity("harold", "bos", "mia", 23, 24, 88);
  199. ds.put(e);
  200. beginTxn();
  201. Flight f = pm.getObjectById(Flight.class, e.getKey());
  202. // make a copy right away, otherwise our change will get reverted
  203. // when the txn rolls back
  204. Flight fCopy = pm.detachCopy(f);
  205. ExceptionThrowingDatastoreDelegate dd =
  206. new ExceptionThrowingDatastoreDelegate(getDelegateForThread(), policy);
  207. setDelegateForThread(dd);
  208. try {
  209. // update attached object
  210. fCopy.setYou(12);
  211. pm.makePersistent(fCopy);
  212. try {
  213. commitTxn();
  214. fail("expected exception");
  215. } catch (JDODataStoreException ex) {
  216. // good
  217. assertTrue(ex.getCause() instanceof ConcurrentModificationException);
  218. }
  219. assertFalse(pm.currentTransaction().isActive());
  220. beginTxn();
  221. pm.makePersistent(fCopy);
  222. commitTxn();
  223. beginTxn();
  224. f = pm.getObjectById(Flight.class, e.getKey());
  225. assertEquals(f, "harold", "bos", "mia", 12, 24, 88);
  226. commitTxn();
  227. } finally {
  228. setDelegateForThread(dd.getInner());
  229. }
  230. }
  231. public void testDeleteCollides() {
  232. Entity e = Flight.newFlightEntity("harold", "bos", "mia", 23, 24, 88);
  233. ds.put(e);
  234. CollisionDatastoreDelegate dd = new CollisionDatastoreDelegate(getDelegateForThread());
  235. setDelegateForThread(dd);
  236. try {
  237. beginTxn();
  238. Flight f = pm.getObjectById(Flight.class, e.getKey());
  239. try {
  240. pm.deletePersistent(f);
  241. fail("expected exception");
  242. } catch (JDODataStoreException ex) {
  243. // good
  244. assertTrue(ex.getCause() instanceof ConcurrentModificationException);
  245. }
  246. assertTrue(pm.currentTransaction().isActive());
  247. rollbackTxn();
  248. } finally {
  249. setDelegateForThread(dd.getInner());
  250. }
  251. }
  252. public void testInsertCollides_NoTxn() {
  253. switchDatasource(PersistenceManagerFactoryName.nontransactional);
  254. CollisionDatastoreDelegate dd = new CollisionDatastoreDelegate(getDelegateForThread());
  255. setDelegateForThread(dd);
  256. try {
  257. Flight flight = new Flight();
  258. flight.setName("harold");
  259. flight.setOrigin("bos");
  260. flight.setDest("mia");
  261. flight.setYou(23);
  262. flight.setMe(24);
  263. flight.setFlightNumber(88);
  264. try {
  265. pm.makePersistent(flight);
  266. fail("expected exception");
  267. } catch (JDODataStoreException e) {
  268. // good
  269. assertTrue(e.getCause() instanceof ConcurrentModificationException);
  270. }
  271. assertEquals(flight, "harold", "bos", "mia", 23, 24, 88);
  272. } finally {
  273. setDelegateForThread(dd.getInner());
  274. }
  275. }
  276. public void testUpdateCollides_NoTxn() {
  277. switchDatasource(PersistenceManagerFactoryName.nontransactional);
  278. Entity e = Flight.newFlightEntity("harold", "bos", "mia", 23, 24, 88);
  279. ds.put(e);
  280. CollisionDatastoreDelegate dd = new CollisionDatastoreDelegate(getDelegateForThread());
  281. setDelegateForThread(dd);
  282. try {
  283. try {
  284. Flight f = pm.getObjectById(Flight.class, e.getKey());
  285. f.setYou(12);
  286. pm.close();
  287. fail("expected exception");
  288. } catch (JDODataStoreException ex) {
  289. // good
  290. assertTrue(ex.getCause() instanceof ConcurrentModificationException);
  291. } catch (NucleusDataStoreException ex) {
  292. assertTrue(ex.getCause() instanceof ConcurrentModificationException);
  293. }
  294. } finally {
  295. setDelegateForThread(dd.getInner());
  296. }
  297. }
  298. public void testUpdateOfDetachedCollides_NoTxn() {
  299. switchDatasource(PersistenceManagerFactoryName.nontransactional);
  300. Entity e = Flight.newFlightEntity("harold", "bos", "mia", 23, 24, 88);
  301. ds.put(e);
  302. Flight f = pm.detachCopy(pm.getObjectById(Flight.class, e.getKey()));
  303. pm.close();
  304. pm = pmf.getPersistenceManager();
  305. CollisionDatastoreDelegate dd = new CollisionDatastoreDelegate(getDelegateForThread());
  306. setDelegateForThread(dd);
  307. try {
  308. // update detached object
  309. f.setYou(12);
  310. // reattach
  311. try {
  312. pm.makePersistent(f);
  313. pm.close();
  314. fail("expected exception");
  315. } catch (JDODataStoreException ex) {
  316. // good
  317. assertTrue(ex.getCause() instanceof ConcurrentModificationException);
  318. }
  319. // now verify that the new value is still in the detached version.
  320. assertEquals(f, "harold", "bos", "mia", 12, 24, 88);
  321. } finally {
  322. setDelegateForThread(dd.getInner());
  323. }
  324. }
  325. public void testUpdateOfDetachedCollidesThenSucceeds_NoTxn() {
  326. switchDatasource(PersistenceManagerFactoryName.nontransactional);
  327. ExceptionThrowingDatastoreDelegate.ExceptionPolicy policy =
  328. new ExceptionThrowingDatastoreDelegate.BaseExceptionPolicy() {
  329. int count = 0;
  330. protected void doIntercept(String methodName) {
  331. if (count == 0) {
  332. count++;
  333. throw new ConcurrentModificationException();
  334. }
  335. }
  336. };
  337. Entity e = Flight.newFlightEntity("harold", "bos", "mia", 23, 24, 88);
  338. ds.put(e);
  339. Flight f = pm.detachCopy(pm.getObjectById(Flight.class, e.getKey()));
  340. pm.close();
  341. pm = pmf.getPersistenceManager();
  342. ExceptionThrowingDatastoreDelegate dd =
  343. new ExceptionThrowingDatastoreDelegate(getDelegateForThread(), policy);
  344. setDelegateForThread(dd);
  345. try {
  346. // update detached object
  347. f.setYou(12);
  348. // reattach
  349. try {
  350. pm.makePersistent(f);
  351. pm.close();
  352. fail("expected exception");
  353. } catch (JDODataStoreException ex) {
  354. // good
  355. assertTrue(ex.getCause() instanceof ConcurrentModificationException);
  356. }
  357. pm = pmf.getPersistenceManager();
  358. pm.makePersistent(f);
  359. pm.close();
  360. pm = pmf.getPersistenceManager();
  361. f = pm.getObjectById(Flight.class, e.getKey());
  362. assertEquals(f, "harold", "bos", "mia", 12, 24, 88);
  363. pm.close();
  364. } finally {
  365. setDelegateForThread(dd.getInner());
  366. }
  367. }
  368. public void testUpdateOfAttachedCollidesThenSucceeds_NoTxn() {
  369. switchDatasource(PersistenceManagerFactoryName.nontransactional);
  370. ExceptionThrowingDatastoreDelegate.ExceptionPolicy policy =
  371. new ExceptionThrowingDatastoreDelegate.BaseExceptionPolicy() {
  372. int count = 0;
  373. protected void doIntercept(String methodName) {
  374. if (count == 0) {
  375. count++;
  376. throw new ConcurrentModificationException();
  377. }
  378. }
  379. };
  380. Entity e = Flight.newFlightEntity("harold", "bos", "mia", 23, 24, 88);
  381. ds.put(e);
  382. Flight f = pm.getObjectById(Flight.class, e.getKey());
  383. // make a copy right away, otherwise our change will get reverted
  384. // when the txn rolls back
  385. Flight fCopy = pm.detachCopy(f);
  386. ExceptionThrowingDatastoreDelegate dd =
  387. new ExceptionThrowingDatastoreDelegate(getDelegateForThread(), policy);
  388. setDelegateForThread(dd);
  389. try {
  390. // update attached object
  391. fCopy.setYou(12);
  392. try {
  393. pm.makePersistent(fCopy);
  394. pm.close();
  395. fail("expected exception");
  396. } catch (JDODataStoreException ex) {
  397. // good
  398. assertTrue(ex.getCause() instanceof ConcurrentModificationException);
  399. }
  400. pm = pmf.getPersistenceManager();
  401. pm.makePersistent(fCopy);
  402. pm.close();
  403. pm = pmf.getPersistenceManager();
  404. f = pm.getObjectById(Flight.class, e.getKey());
  405. assertEquals(f, "harold", "bos", "mia", 12, 24, 88);
  406. pm.close();
  407. } finally {
  408. setDelegateForThread(dd.getInner());
  409. }
  410. }
  411. public void testDeleteCollides_NoTxn() {
  412. switchDatasource(PersistenceManagerFactoryName.nontransactional);
  413. Entity e = Flight.newFlightEntity("harold", "bos", "mia", 23, 24, 88);
  414. ds.put(e);
  415. CollisionDatastoreDelegate dd = new CollisionDatastoreDelegate(getDelegateForThread());
  416. setDelegateForThread(dd);
  417. try {
  418. Flight f = pm.getObjectById(Flight.class, e.getKey());
  419. try {
  420. pm.deletePersistent(f);
  421. fail("expected exception");
  422. } catch (JDODataStoreException ex) {
  423. // good
  424. assertTrue(ex.getCause() instanceof ConcurrentModificationException);
  425. }
  426. pm.close();
  427. } finally {
  428. setDelegateForThread(dd.getInner());
  429. }
  430. }
  431. private void assertEquals(Flight f, String name, String orig, String dest, int you, int me, int flightNumber) {
  432. assertEquals(name, f.getName());
  433. assertEquals(orig, f.getOrigin());
  434. assertEquals(dest, f.getDest());
  435. assertEquals(you, f.getYou());
  436. assertEquals(me, f.getMe());
  437. assertEquals(flightNumber, f.getFlightNumber());
  438. }
  439. }