PageRenderTime 69ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/com/google/appengine/datanucleus/jpa/JPAConcurrentModificationTest.java

http://datanucleus-appengine.googlecode.com/
Java | 496 lines | 407 code | 46 blank | 43 comment | 10 complexity | 393b245c67f4b17998df6ba42af1a8fe MD5 | raw file
Possible License(s): Apache-2.0
  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.jpa;
  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.jpa.Book;
  23. import java.util.ConcurrentModificationException;
  24. import javax.persistence.PersistenceException;
  25. import javax.persistence.RollbackException;
  26. import org.datanucleus.exceptions.NucleusDataStoreException;
  27. /**
  28. * @author Max Ross <maxr@google.com>
  29. */
  30. @Inner
  31. public class JPAConcurrentModificationTest extends JPATestCase {
  32. public void testInsertCollides() {
  33. CollisionDatastoreDelegate dd = new CollisionDatastoreDelegate(getDelegateForThread());
  34. setDelegateForThread(dd);
  35. try {
  36. Book book = new Book();
  37. book.setAuthor("harold");
  38. book.setIsbn("1234");
  39. book.setFirstPublished(1888);
  40. book.setTitle("the title");
  41. beginTxn();
  42. try {
  43. em.persist(book);
  44. commitTxn();
  45. fail("expected exception");
  46. } catch (RollbackException e) {
  47. // good
  48. assertTrue(e.getCause() instanceof PersistenceException);
  49. assertTrue(e.getCause().getCause() instanceof ConcurrentModificationException);
  50. }
  51. assertFalse(em.getTransaction().isActive());
  52. assertEquals(book, "harold", "1234", 1888, "the title");
  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. Book book = new Book();
  73. book.setAuthor("harold");
  74. book.setIsbn("1234");
  75. book.setFirstPublished(1888);
  76. book.setTitle("the title");
  77. beginTxn();
  78. try {
  79. em.persist(book);
  80. commitTxn();
  81. fail("expected exception");
  82. } catch (RollbackException e) {
  83. // good
  84. assertTrue(e.getCause() instanceof PersistenceException);
  85. assertTrue(e.getCause().getCause() instanceof NucleusDataStoreException);
  86. assertTrue(e.getCause().getCause().getCause() instanceof ConcurrentModificationException);
  87. }
  88. assertFalse(em.getTransaction().isActive());
  89. assertEquals(book, "harold", "1234", 1888, "the title");
  90. } finally {
  91. setDelegateForThread(dd.getInner());
  92. }
  93. }
  94. public void testUpdateCollides() {
  95. Entity e = Book.newBookEntity("harold", "1234", "the title");
  96. ds.put(e);
  97. CollisionDatastoreDelegate dd =
  98. new CollisionDatastoreDelegate(getDelegateForThread());
  99. setDelegateForThread(dd);
  100. try {
  101. beginTxn();
  102. Book b = em.find(Book.class, e.getKey());
  103. try {
  104. b.setFirstPublished(1998);
  105. commitTxn();
  106. fail("expected exception");
  107. } catch (RollbackException ex) {
  108. // good
  109. assertTrue(ex.getCause() instanceof PersistenceException);
  110. assertTrue(ex.getCause().getCause() instanceof ConcurrentModificationException);
  111. }
  112. assertFalse(em.getTransaction().isActive());
  113. assertEquals(b, "harold", "1234", 2000, "the title");
  114. } finally {
  115. setDelegateForThread(dd.getInner());
  116. }
  117. }
  118. public void testUpdateOfDetachedCollides() {
  119. Entity e = Book.newBookEntity("harold", "1234", "the title");
  120. ds.put(e);
  121. beginTxn();
  122. Book book = em.find(Book.class, e.getKey());
  123. commitTxn();
  124. CollisionDatastoreDelegate dd = new CollisionDatastoreDelegate(getDelegateForThread());
  125. setDelegateForThread(dd);
  126. try {
  127. try {
  128. // update detached object TODO The object here is not "detached" at all. It is HOLLOW
  129. book.setFirstPublished(1988);
  130. beginTxn();
  131. // reattach
  132. em.merge(book);
  133. commitTxn();
  134. fail("expected exception");
  135. } catch (RollbackException ex) {
  136. // good
  137. assertTrue(ex.getCause() instanceof PersistenceException);
  138. assertTrue(ex.getCause().getCause() instanceof ConcurrentModificationException);
  139. } catch (NucleusDataStoreException nde) {
  140. assertTrue(nde.getCause() instanceof ConcurrentModificationException);
  141. }
  142. assertFalse(em.getTransaction().isActive());
  143. // now verify that the new value is still in the detached version.
  144. assertEquals(book, "harold", "1234", 1988, "the title");
  145. } finally {
  146. setDelegateForThread(dd.getInner());
  147. }
  148. }
  149. public void testUpdateOfDetachedCollidesThenSucceeds() {
  150. ExceptionThrowingDatastoreDelegate.ExceptionPolicy policy =
  151. new ExceptionThrowingDatastoreDelegate.BaseExceptionPolicy() {
  152. int count = 0;
  153. protected void doIntercept(String methodName) {
  154. if (count == 0) {
  155. count++;
  156. throw new ConcurrentModificationException();
  157. }
  158. }
  159. };
  160. Entity e = Book.newBookEntity("harold", "1234", "the title");
  161. ds.put(e);
  162. beginTxn();
  163. Book book = em.find(Book.class, e.getKey());
  164. commitTxn();
  165. ExceptionThrowingDatastoreDelegate dd =
  166. new ExceptionThrowingDatastoreDelegate(getDelegateForThread(), policy);
  167. setDelegateForThread(dd);
  168. try {
  169. try {
  170. // update detached object TODO The object here is not "detached" at all. It is HOLLOW
  171. book.setFirstPublished(1988);
  172. beginTxn();
  173. // reattach
  174. em.merge(book);
  175. commitTxn();
  176. fail("expected exception");
  177. } catch (RollbackException ex) {
  178. // good
  179. assertTrue(ex.getCause() instanceof PersistenceException);
  180. assertTrue(ex.getCause().getCause() instanceof ConcurrentModificationException);
  181. } catch (NucleusDataStoreException nde) {
  182. assertTrue(nde.getCause() instanceof ConcurrentModificationException);
  183. }
  184. assertFalse(em.getTransaction().isActive());
  185. beginTxn();
  186. book.setFirstPublished(1989);
  187. em.merge(book);
  188. commitTxn();
  189. beginTxn();
  190. book = em.find(Book.class, e.getKey());
  191. assertEquals(book, "harold", "1234", 1989, "the title");
  192. commitTxn();
  193. } finally {
  194. setDelegateForThread(dd.getInner());
  195. }
  196. }
  197. public void testUpdateOfAttachedCollidesThenSucceeds() {
  198. ExceptionThrowingDatastoreDelegate.ExceptionPolicy policy =
  199. new ExceptionThrowingDatastoreDelegate.BaseExceptionPolicy() {
  200. int count = 0;
  201. protected void doIntercept(String methodName) {
  202. if (count == 0) {
  203. count++;
  204. throw new ConcurrentModificationException();
  205. }
  206. }
  207. };
  208. Entity e = Book.newBookEntity("harold", "1234", "the title");
  209. ds.put(e);
  210. beginTxn();
  211. Book b = em.find(Book.class, e.getKey());
  212. ExceptionThrowingDatastoreDelegate dd =
  213. new ExceptionThrowingDatastoreDelegate(getDelegateForThread(), policy);
  214. setDelegateForThread(dd);
  215. try {
  216. try {
  217. // update attached object TODO The object here is not "detached" at all. It is HOLLOW
  218. b.setFirstPublished(1988);
  219. commitTxn();
  220. fail("expected exception");
  221. } catch (RollbackException ex) {
  222. // good
  223. assertTrue(ex.getCause() instanceof PersistenceException);
  224. assertTrue(ex.getCause().getCause() instanceof ConcurrentModificationException);
  225. }
  226. // rollback of txn causes state of pojo to rollback as well
  227. assertEquals(2000, b.getFirstPublished());
  228. assertFalse(em.getTransaction().isActive());
  229. beginTxn();
  230. // reapply the change
  231. b.setFirstPublished(1988);
  232. em.merge(b);
  233. commitTxn();
  234. beginTxn();
  235. b = em.find(Book.class, e.getKey());
  236. assertEquals(b, "harold", "1234", 1988, "the title");
  237. commitTxn();
  238. } finally {
  239. setDelegateForThread(dd.getInner());
  240. }
  241. }
  242. public void testDeleteCollides() {
  243. Entity e = Book.newBookEntity("harold", "1234", "the title");
  244. ds.put(e);
  245. CollisionDatastoreDelegate dd = new CollisionDatastoreDelegate(getDelegateForThread());
  246. setDelegateForThread(dd);
  247. try {
  248. beginTxn();
  249. Book b = em.find(Book.class, e.getKey());
  250. em.remove(b);
  251. try {
  252. commitTxn();
  253. fail("expected exception");
  254. } catch (RollbackException ex) {
  255. // good
  256. assertTrue(ex.getCause() instanceof PersistenceException);
  257. assertTrue(ex.getCause().getCause() instanceof ConcurrentModificationException);
  258. }
  259. } finally {
  260. setDelegateForThread(dd.getInner());
  261. }
  262. }
  263. public void testInsertCollides_NoTxn() {
  264. switchDatasource(EntityManagerFactoryName.nontransactional_ds_non_transactional_ops_allowed);
  265. CollisionDatastoreDelegate dd = new CollisionDatastoreDelegate(getDelegateForThread());
  266. setDelegateForThread(dd);
  267. try {
  268. Book book = new Book();
  269. book.setAuthor("harold");
  270. book.setIsbn("1234");
  271. book.setFirstPublished(1988);
  272. book.setTitle("the title");
  273. try {
  274. em.persist(book);
  275. em.close();
  276. fail("expected exception");
  277. } catch (PersistenceException e) {
  278. assertTrue(e.getCause() instanceof ConcurrentModificationException);
  279. }
  280. assertEquals(book, "harold", "1234", 1988, "the title");
  281. } finally {
  282. setDelegateForThread(dd.getInner());
  283. }
  284. }
  285. public void testUpdateCollides_NoTxn() {
  286. switchDatasource(EntityManagerFactoryName.nontransactional_ds_non_transactional_ops_allowed);
  287. Entity e = Book.newBookEntity("harold", "1234", "the title");
  288. ds.put(e);
  289. CollisionDatastoreDelegate dd = new CollisionDatastoreDelegate(getDelegateForThread());
  290. setDelegateForThread(dd);
  291. try {
  292. Book b = em.find(Book.class, e.getKey());
  293. try {
  294. b.setFirstPublished(1988);
  295. em.close();
  296. fail("expected exception");
  297. } catch (PersistenceException ex) {
  298. assertTrue(ex.getCause() instanceof ConcurrentModificationException);
  299. } catch (NucleusDataStoreException nde) {
  300. assertTrue(nde.getCause() instanceof ConcurrentModificationException);
  301. }
  302. assertEquals(b, "harold", "1234", 1988, "the title");
  303. } finally {
  304. setDelegateForThread(dd.getInner());
  305. }
  306. }
  307. public void testUpdateOfDetachedCollides_NoTxn() {
  308. switchDatasource(EntityManagerFactoryName.nontransactional_ds_non_transactional_ops_allowed);
  309. Entity e = Book.newBookEntity("harold", "1234", "the title");
  310. ds.put(e);
  311. // DataNuc JPA impl won't detach the object unless you open and close a txn ... like the JPA spec says
  312. beginTxn();
  313. Book book = em.find(Book.class, e.getKey());
  314. commitTxn();
  315. em.close();
  316. em = emf.createEntityManager();
  317. CollisionDatastoreDelegate dd = new CollisionDatastoreDelegate(getDelegateForThread());
  318. setDelegateForThread(dd);
  319. try {
  320. // update detached object
  321. book.setFirstPublished(1988);
  322. try {
  323. // reattach
  324. em.merge(book);
  325. em.close();
  326. fail("expected exception");
  327. } catch (PersistenceException ex) {
  328. assertTrue(ex.getCause() instanceof ConcurrentModificationException);
  329. }
  330. // now verify that the new value is still in the detached version.
  331. assertEquals(book, "harold", "1234", 1988, "the title");
  332. } finally {
  333. setDelegateForThread(dd.getInner());
  334. }
  335. }
  336. public void testUpdateOfDetachedCollidesThenSucceeds_NoTxn() {
  337. switchDatasource(EntityManagerFactoryName.nontransactional_ds_non_transactional_ops_allowed);
  338. ExceptionThrowingDatastoreDelegate.ExceptionPolicy policy =
  339. new ExceptionThrowingDatastoreDelegate.BaseExceptionPolicy() {
  340. int count = 0;
  341. protected void doIntercept(String methodName) {
  342. if (count == 0) {
  343. count++;
  344. throw new ConcurrentModificationException();
  345. }
  346. }
  347. };
  348. Entity e = Book.newBookEntity("harold", "1234", "the title");
  349. ds.put(e);
  350. beginTxn();
  351. Book b = em.find(Book.class, e.getKey());
  352. commitTxn();
  353. em.close();
  354. em = emf.createEntityManager();
  355. ExceptionThrowingDatastoreDelegate dd =
  356. new ExceptionThrowingDatastoreDelegate(getDelegateForThread(), policy);
  357. setDelegateForThread(dd);
  358. try {
  359. // update detached object
  360. b.setFirstPublished(1988);
  361. // reattach
  362. try {
  363. em.merge(b);
  364. em.close();
  365. fail("expected exception");
  366. } catch (PersistenceException ex) {
  367. assertTrue(ex.getCause() instanceof ConcurrentModificationException);
  368. }
  369. em = emf.createEntityManager();
  370. em.merge(b);
  371. em.close();
  372. em = emf.createEntityManager();
  373. b = em.find(Book.class, e.getKey());
  374. assertEquals(b, "harold", "1234", 1988, "the title");
  375. em.close();
  376. } finally {
  377. setDelegateForThread(dd.getInner());
  378. }
  379. }
  380. public void testUpdateOfAttachedCollidesThenSucceeds_NoTxn() {
  381. switchDatasource(EntityManagerFactoryName.nontransactional_ds_non_transactional_ops_allowed);
  382. ExceptionThrowingDatastoreDelegate.ExceptionPolicy policy =
  383. new ExceptionThrowingDatastoreDelegate.BaseExceptionPolicy() {
  384. int count = 0;
  385. protected void doIntercept(String methodName) {
  386. if (count == 0) {
  387. count++;
  388. throw new ConcurrentModificationException();
  389. }
  390. }
  391. };
  392. Entity e = Book.newBookEntity("harold", "1234", "the title");
  393. ds.put(e);
  394. Book b = em.find(Book.class, e.getKey());
  395. // make a copy right away, otherwise our change will get reverted when the txn rolls back
  396. ExceptionThrowingDatastoreDelegate dd =
  397. new ExceptionThrowingDatastoreDelegate(getDelegateForThread(), policy);
  398. setDelegateForThread(dd);
  399. try {
  400. // update attached object
  401. try {
  402. b.setFirstPublished(1988);
  403. em.merge(b);
  404. em.close();
  405. fail("expected exception");
  406. } catch (PersistenceException ex) {
  407. assertTrue(ex.getCause() instanceof ConcurrentModificationException);
  408. } catch (NucleusDataStoreException nde) {
  409. assertTrue(nde.getCause() instanceof ConcurrentModificationException);
  410. }
  411. em = emf.createEntityManager();
  412. b = em.find(Book.class, e.getKey());
  413. // update attached object
  414. b.setFirstPublished(1988);
  415. em.merge(b);
  416. em.close();
  417. em = emf.createEntityManager();
  418. b = em.find(Book.class, e.getKey());
  419. assertEquals(b, "harold", "1234", 1988, "the title");
  420. em.close();
  421. } finally {
  422. setDelegateForThread(dd.getInner());
  423. }
  424. }
  425. public void testDeleteCollides_NoTxn() {
  426. switchDatasource(EntityManagerFactoryName.nontransactional_ds_non_transactional_ops_allowed);
  427. Entity e = Book.newBookEntity("harold", "1234", "the title");
  428. ds.put(e);
  429. CollisionDatastoreDelegate dd = new CollisionDatastoreDelegate(getDelegateForThread());
  430. setDelegateForThread(dd);
  431. try {
  432. Book b = em.find(Book.class, e.getKey());
  433. try {
  434. em.remove(b);
  435. em.close();
  436. fail("expected exception");
  437. } catch (PersistenceException ex) {
  438. assertTrue(ex.getCause() instanceof ConcurrentModificationException);
  439. }
  440. } finally {
  441. setDelegateForThread(dd.getInner());
  442. }
  443. }
  444. private void assertEquals(Book book, String author, String isbn, int firstPublished, String title) {
  445. assertEquals(author, book.getAuthor());
  446. assertEquals(isbn, book.getIsbn());
  447. assertEquals(firstPublished, book.getFirstPublished());
  448. assertEquals(title, book.getTitle());
  449. }
  450. }