PageRenderTime 87ms CodeModel.GetById 14ms app.highlight 67ms RepoModel.GetById 1ms app.codeStats 0ms

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

http://datanucleus-appengine.googlecode.com/
Java | 692 lines | 574 code | 84 blank | 34 comment | 0 complexity | 7e3234e78f133835485bc5c0c435b8f1 MD5 | raw file
  1/**********************************************************************
  2Copyright (c) 2009 Google Inc.
  3
  4Licensed under the Apache License, Version 2.0 (the "License");
  5you may not use this file except in compliance with the License.
  6You may obtain a copy of the License at
  7
  8http://www.apache.org/licenses/LICENSE-2.0
  9
 10Unless required by applicable law or agreed to in writing, software
 11distributed under the License is distributed on an "AS IS" BASIS,
 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13See the License for the specific language governing permissions and
 14limitations under the License.
 15**********************************************************************/
 16package com.google.appengine.datanucleus.jdo;
 17
 18import com.google.appengine.api.datastore.Entity;
 19import com.google.appengine.api.datastore.EntityNotFoundException;
 20import com.google.appengine.api.datastore.Key;
 21import com.google.appengine.api.datastore.KeyFactory;
 22import com.google.appengine.datanucleus.DatastoreManager;
 23import com.google.appengine.datanucleus.test.jdo.SubclassesJDO;
 24import com.google.appengine.datanucleus.test.jdo.SubclassesJDO.CompleteTableParentNoChildStrategy;
 25import com.google.appengine.datanucleus.test.jdo.SubclassesJDO.CompleteTableParentWithCompleteTableChild;
 26import com.google.appengine.datanucleus.test.jdo.SubclassesJDO.CompleteTableParentWithEmbedded;
 27import com.google.appengine.datanucleus.test.jdo.SubclassesJDO.CompleteTableParentWithNewTableChild;
 28import com.google.appengine.datanucleus.test.jdo.SubclassesJDO.CompleteTableParentWithSubclassTableChild;
 29import com.google.appengine.datanucleus.test.jdo.SubclassesJDO.DurableChild;
 30import com.google.appengine.datanucleus.test.jdo.SubclassesJDO.Grandchild;
 31import com.google.appengine.datanucleus.test.jdo.SubclassesJDO.NewTableParentWithCompleteTableChild;
 32import com.google.appengine.datanucleus.test.jdo.SubclassesJDO.NewTableParentWithNewTableChild;
 33import com.google.appengine.datanucleus.test.jdo.SubclassesJDO.NewTableParentWithSubclassTableChild;
 34import com.google.appengine.datanucleus.test.jdo.SubclassesJDO.OverrideParent;
 35import com.google.appengine.datanucleus.test.jdo.SubclassesJDO.Parent;
 36import com.google.appengine.datanucleus.test.jdo.SubclassesJDO.SubclassTableParentWithCompleteTableChild;
 37import com.google.appengine.datanucleus.test.jdo.SubclassesJDO.SubclassTableParentWithNewTableChild;
 38import com.google.appengine.datanucleus.test.jdo.SubclassesJDO.SubclassTableParentWithSubclassTableChild;
 39
 40import org.datanucleus.api.jdo.exceptions.NoPersistenceInformationException;
 41
 42import java.util.List;
 43
 44import javax.jdo.JDOFatalUserException;
 45import javax.jdo.Query;
 46
 47/**
 48 * There's something flaky here that will probably show up as a real bug at
 49 * some point.  If the Parent class gets used first, the subclass
 50 * tests fail.  To get around this I'm just running the subclass tests
 51 * first.  There's definitely something funny going on though.
 52 *
 53 * @author Max Ross <maxr@google.com>
 54 */
 55// TODO(maxr): non-transactional tests
 56public class JDOSubclassTest extends JDOTestCase {
 57
 58  public void testGrandchildren() throws Exception {
 59    testGrandchild(new CompleteTableParentWithCompleteTableChild.Child.Grandchild());
 60    testGrandchild(new CompleteTableParentNoChildStrategy.Child.Grandchild());
 61    testGrandchild(new SubclassTableParentWithCompleteTableChild.Child.Grandchild());
 62  }
 63
 64  public void testChildren() throws Exception {
 65    testChild(new CompleteTableParentWithCompleteTableChild.Child());
 66    testChild(new CompleteTableParentNoChildStrategy.Child());
 67    testChild(new SubclassTableParentWithCompleteTableChild.Child());
 68    testChild(new SubclassTableParentWithNewTableChild.Child());
 69    testChild(new NewTableParentWithCompleteTableChild.Child());
 70  }
 71
 72  public void testUnsupportedStrategies_GAE() {
 73    assertUnsupportedByGAE(new NewTableParentWithNewTableChild.Child());
 74    assertUnsupportedByGAE(new CompleteTableParentWithNewTableChild.Child());
 75    assertUnsupportedByGAE(new SubclassTableParentWithNewTableChild.Child.Grandchild());
 76  }
 77
 78  public void testUnsupportedStrategies_DataNuc() throws Exception {
 79    assertUnsupportedByDataNuc(new SubclassTableParentWithSubclassTableChild.Child());
 80    assertUnsupportedByDataNuc(new SubclassTableParentWithCompleteTableChild());
 81  }
 82
 83  public void testParents() throws Exception {
 84    testParent(new CompleteTableParentWithCompleteTableChild());
 85    testParent(new CompleteTableParentWithNewTableChild());
 86    testParent(new CompleteTableParentWithSubclassTableChild());
 87    testParent(new CompleteTableParentNoChildStrategy());
 88    testParent(new NewTableParentWithCompleteTableChild());
 89    testParent(new NewTableParentWithSubclassTableChild());
 90    testParent(new NewTableParentWithNewTableChild());
 91  }
 92
 93  public void testOverride() throws Exception {
 94    OverrideParent.Child child = new OverrideParent.Child();
 95    child.setOverriddenString("blarg");
 96    beginTxn();
 97    pm.makePersistent(child);
 98    commitTxn();
 99
100    Entity e = ds.get(KeyFactory.createKey(kindForClass(child.getClass()), child.getId()));
101    assertEquals("blarg", e.getProperty("overridden_string"));
102    assertFalse(e.hasProperty("overriddenProperty"));
103  }
104
105  public void testEmbedded_Child() throws Exception {
106    CompleteTableParentWithEmbedded.Child child = new CompleteTableParentWithEmbedded.Child();
107    child.setAString("aString");
108    child.setBString("bString");
109    SubclassesJDO.IsEmbeddedOnly embedded = new SubclassesJDO.IsEmbeddedOnly();
110    embedded.setVal0("embedded val 0");
111    embedded.setVal1("embedded val 1");
112    child.setEmbedded(embedded);
113    SubclassesJDO.IsEmbeddedOnlyBase embeddedBase = new SubclassesJDO.IsEmbeddedOnlyBase();
114    embeddedBase.setVal0("embedded base val 0");
115    child.setEmbeddedBase(embeddedBase);
116    SubclassesJDO.IsEmbeddedOnly2 embedded2 = new SubclassesJDO.IsEmbeddedOnly2();
117    embedded2.setVal2("embedded val 2");
118    embedded2.setVal3("embedded val 3");
119    child.setEmbedded2(embedded2);
120    SubclassesJDO.IsEmbeddedOnlyBase2 embeddedBase2 = new SubclassesJDO.IsEmbeddedOnlyBase2();
121    embeddedBase2.setVal2("embedded base val 2");
122    child.setEmbeddedBase2(embeddedBase2);
123    beginTxn();
124    pm.makePersistent(child);
125    commitTxn();
126    Key key = KeyFactory.createKey(kindForClass(child.getClass()), child.getId());
127    Entity e = ds.get(key);
128    assertEquals("aString", e.getProperty("aString"));
129    assertEquals("bString", e.getProperty("bString"));
130    assertEquals("embedded val 0", e.getProperty("val0"));
131    assertEquals("embedded val 1", e.getProperty("val1"));
132    assertEquals("embedded base val 0", e.getProperty("VAL0"));
133    assertEquals("embedded val 2", e.getProperty("val2"));
134    assertEquals("embedded val 3", e.getProperty("val3"));
135    assertEquals("embedded base val 2", e.getProperty("VAL2"));
136    pm.close();
137    pm = pmf.getPersistenceManager();
138    beginTxn();
139    child = pm.getObjectById(child.getClass(), child.getId());
140    assertEmbeddedChildContents(child);
141    commitTxn();
142    pm.close();
143    pm = pmf.getPersistenceManager();
144    beginTxn();
145    Query q = pm.newQuery("select from " + child.getClass().getName() + " where embedded.val1 == :p "
146      + "order by embedded.val1 desc, embedded.val0 desc, embeddedBase.val0 desc, "
147      + "embedded2.val2 desc, embedded2.val3 desc, embeddedBase2.val2");
148    q.setUnique(true);
149    child = (CompleteTableParentWithEmbedded.Child) q.execute("embedded val 1");
150    assertEmbeddedChildContents(child);
151
152    q = pm.newQuery("select from " + child.getClass().getName() + " where embedded.val0 == :p "
153      + "order by embedded.val1 desc, embedded.val0 desc, embeddedBase.val0 desc, "
154      + "embedded2.val2 desc, embedded2.val3 desc, embeddedBase2.val2");
155    q.setUnique(true);
156    child = (CompleteTableParentWithEmbedded.Child) q.execute("embedded val 0");
157    assertEmbeddedChildContents(child);
158
159    q = pm.newQuery("select from " + child.getClass().getName() + " where embeddedBase.val0 == :p "
160      + "order by embedded.val1 desc, embedded.val0 desc, embeddedBase.val0 desc, "
161      + "embedded2.val2 desc, embedded2.val3 desc, embeddedBase2.val2");
162    q.setUnique(true);
163    child = (CompleteTableParentWithEmbedded.Child) q.execute("embedded base val 0");
164    assertEmbeddedChildContents(child);
165
166    q = pm.newQuery("select from " + child.getClass().getName() + " where embedded2.val2 == :p "
167      + "order by embedded.val1 desc, embedded.val0 desc, embeddedBase.val0 desc, "
168      + "embedded2.val2 desc, embedded2.val3 desc, embeddedBase2.val2");
169    q.setUnique(true);
170    child = (CompleteTableParentWithEmbedded.Child) q.execute("embedded val 2");
171    assertEmbeddedChildContents(child);
172
173    q = pm.newQuery("select from " + child.getClass().getName() + " where embedded2.val3 == :p "
174      + "order by embedded.val1 desc, embedded.val0 desc, embeddedBase.val0 desc, "
175      + "embedded2.val2 desc, embedded2.val3 desc, embeddedBase2.val2");
176    q.setUnique(true);
177    child = (CompleteTableParentWithEmbedded.Child) q.execute("embedded val 3");
178    assertEmbeddedChildContents(child);
179
180    q = pm.newQuery("select from " + child.getClass().getName() + " where embeddedBase2.val2 == :p "
181      + "order by embedded.val1 desc, embedded.val0 desc, embeddedBase.val0 desc, "
182      + "embedded2.val2 desc, embedded2.val3 desc, embeddedBase2.val2");
183    q.setUnique(true);
184    child = (CompleteTableParentWithEmbedded.Child) q.execute("embedded base val 2");
185    assertEmbeddedChildContents(child);
186
187    q = pm.newQuery("select embedded.val1, embedded.val0, embeddedBase.val0, embedded2.val2, embedded2.val3, embeddedBase2.val2 from " +
188                    child.getClass().getName() + " where embeddedBase2.val2 == :p");
189    q.setUnique(true);
190    Object[] result = (Object[]) q.execute("embedded base val 2");
191    assertEquals("embedded val 1", result[0]);
192    assertEquals("embedded val 0", result[1]);
193    assertEquals("embedded base val 0", result[2]);
194    assertEquals("embedded val 2", result[3]);
195    assertEquals("embedded val 3", result[4]);
196    assertEquals("embedded base val 2", result[5]);
197
198    pm.deletePersistent(child);
199    commitTxn();
200    try {
201      ds.get(key);
202      fail("expected enfe");
203    } catch (EntityNotFoundException enfe) {
204      // good
205    }
206  }
207
208  public void testEmbedded_Parent() throws Exception {
209    CompleteTableParentWithEmbedded parent = new CompleteTableParentWithEmbedded();
210    parent.setAString("aString");
211    SubclassesJDO.IsEmbeddedOnly embedded = new SubclassesJDO.IsEmbeddedOnly();
212    embedded.setVal0("embedded val 0");
213    embedded.setVal1("embedded val 1");
214    parent.setEmbedded(embedded);
215    SubclassesJDO.IsEmbeddedOnlyBase embeddedBase = new SubclassesJDO.IsEmbeddedOnlyBase();
216    embeddedBase.setVal0("embedded base val 0");
217    parent.setEmbeddedBase(embeddedBase);
218    beginTxn();
219    pm.makePersistent(parent);
220    commitTxn();
221    Key key = KeyFactory.createKey(kindForClass(parent.getClass()), parent.getId());
222    Entity e = ds.get(key);
223    assertEquals("aString", e.getProperty("aString"));
224    assertEquals("embedded val 0", e.getProperty("val0"));
225    assertEquals("embedded val 1", e.getProperty("val1"));
226    assertEquals("embedded base val 0", e.getProperty("VAL0"));
227    pm.close();
228    pm = pmf.getPersistenceManager();
229    beginTxn();
230    parent = pm.getObjectById(parent.getClass(), parent.getId());
231    assertEmbeddedParentContents(parent);
232    commitTxn();
233    pm.close();
234    pm = pmf.getPersistenceManager();
235    beginTxn();
236    Query q = pm.newQuery(
237        "select from " + parent.getClass().getName() + " where embedded.val1 == :p "
238        + "order by embedded.val1 desc, embedded.val0 asc, embeddedBase.val0 desc");
239    q.setUnique(true);
240    parent = (CompleteTableParentWithEmbedded) q.execute("embedded val 1");
241    assertEmbeddedParentContents(parent);
242
243    q = pm.newQuery(
244        "select from " + parent.getClass().getName() + " where embedded.val0 == :p "
245        + "order by embedded.val1 desc, embedded.val0 asc, embeddedBase.val0 desc");
246    q.setUnique(true);
247    parent = (CompleteTableParentWithEmbedded) q.execute("embedded val 0");
248    assertEmbeddedParentContents(parent);
249
250    q = pm.newQuery(
251        "select from " + parent.getClass().getName() + " where embeddedBase.val0 == :p "
252        + "order by embedded.val1 desc, embedded.val0 asc, embeddedBase.val0 desc");
253    q.setUnique(true);
254    parent = (CompleteTableParentWithEmbedded) q.execute("embedded base val 0");
255    assertEmbeddedParentContents(parent);
256
257    q = pm.newQuery("select embedded.val1, embedded.val0, embeddedBase.val0 from " +
258                    parent.getClass().getName() + " where embeddedBase.val0 == :p "
259        + "order by embedded.val1 desc, embedded.val0 asc, embeddedBase.val0 desc");
260    q.setUnique(true);
261    Object[] result = (Object[]) q.execute("embedded base val 0");
262    assertEquals("embedded val 1", result[0]);
263    assertEquals("embedded val 0", result[1]);
264    assertEquals("embedded base val 0", result[2]);
265
266    pm.deletePersistent(parent);
267    commitTxn();
268    try {
269      ds.get(key);
270      fail("expected enfe");
271    } catch (EntityNotFoundException enfe) {
272      // good
273    }
274  }
275
276  public void testNondurableParent() {
277    DurableChild dc = new DurableChild();
278    dc.setStr("yar");
279    beginTxn();
280    pm.makePersistent(dc);
281    commitTxn();
282    beginTxn();
283    dc = pm.getObjectById(DurableChild.class, dc.getId());
284    assertEquals("yar", dc.getStr());
285  }
286
287  // This is absurd, but if the signature of this method and the one below
288  // refers to the actual type we want the runtime enhancer gets totally
289  // confused.
290  private void assertEmbeddedChildContents(Object obj) {
291    CompleteTableParentWithEmbedded.Child child = (CompleteTableParentWithEmbedded.Child) obj;
292    assertEquals("bString", child.getBString());
293    assertEquals("embedded val 2", child.getEmbedded2().getVal2());
294    assertEquals("embedded val 3", child.getEmbedded2().getVal3());
295    assertEquals("embedded base val 2", child.getEmbeddedBase2().getVal2());
296    assertEmbeddedParentContents(child);
297  }
298
299  private void assertEmbeddedParentContents(Object obj) {
300    CompleteTableParentWithEmbedded parentWithEmbedded = (CompleteTableParentWithEmbedded) obj;
301    assertEquals("aString", parentWithEmbedded.getAString());
302    assertEquals("embedded val 0", parentWithEmbedded.getEmbedded().getVal0());
303    assertEquals("embedded val 1", parentWithEmbedded.getEmbedded().getVal1());
304    assertEquals("embedded base val 0", parentWithEmbedded.getEmbeddedBase().getVal0());
305  }
306
307  private void assertUnsupportedByDataNuc(Object obj) {
308    switchDatasource(PersistenceManagerFactoryName.transactional);
309    beginTxn();
310    try {
311      pm.makePersistent(obj);
312      fail("expected exception");
313    } catch (NoPersistenceInformationException e) {
314      // good
315    }
316    rollbackTxn();
317  }
318
319  private void assertUnsupportedByGAE(Object obj) {
320    switchDatasource(PersistenceManagerFactoryName.transactional);
321    beginTxn();
322    try {
323      pm.makePersistent(obj);
324      fail("expected exception");
325    } catch (JDOFatalUserException e) {
326      // good
327      assertTrue(e.getCause().getClass().getName(),
328                 DatastoreManager.UnsupportedInheritanceStrategyException.class.isAssignableFrom(e.getCause().getClass()));
329    }
330    rollbackTxn();
331  }
332
333  private void testInsertParent(Parent parent) throws Exception {
334    parent.setAString("a");
335    beginTxn();
336    pm.makePersistent(parent);
337    commitTxn();
338
339    Entity e = ds.get(KeyFactory.createKey(kindForClass(parent.getClass()), parent.getId()));
340    assertEquals("a", e.getProperty("aString"));
341  }
342
343  private void testInsertChild(SubclassesJDO.Child child) throws Exception {
344    child.setAString("a");
345    child.setBString("b");
346    beginTxn();
347    pm.makePersistent(child);
348    commitTxn();
349
350    Entity e = ds.get(KeyFactory.createKey(kindForClass(child.getClass()), child.getId()));
351    assertEquals("a", e.getProperty("aString"));
352    assertEquals("b", e.getProperty("bString"));
353  }
354
355  private void testInsertGrandchild(com.google.appengine.datanucleus.test.jdo.SubclassesJDO.Grandchild grandchild) throws Exception {
356    grandchild.setAString("a");
357    grandchild.setBString("b");
358    grandchild.setCString("c");
359    beginTxn();
360    pm.makePersistent(grandchild);
361    commitTxn();
362
363    Entity e = ds.get(KeyFactory.createKey(kindForClass(grandchild.getClass()), grandchild.getId()));
364    assertEquals("a", e.getProperty("aString"));
365    assertEquals("b", e.getProperty("bString"));
366    assertEquals("c", e.getProperty("cString"));
367  }
368
369  private void testFetchParent(Class<? extends Parent> parentClass) {
370    Entity e = new Entity(kindForClass(parentClass));
371    e.setProperty("aString", "a");
372    ds.put(e);
373
374    beginTxn();
375    Parent parent = pm.getObjectById(parentClass, e.getKey());
376    assertEquals(parentClass, parent.getClass());
377    assertEquals("a", parent.getAString());
378    commitTxn();
379  }
380
381  private void testFetchChild(Class<? extends SubclassesJDO.Child> childClass) {
382    Entity e = new Entity(kindForClass(childClass));
383    e.setProperty("aString", "a");
384    e.setProperty("bString", "b");
385    ds.put(e);
386
387    beginTxn();
388    SubclassesJDO.Child child = pm.getObjectById(childClass, e.getKey());
389    assertEquals(childClass, child.getClass());
390    assertEquals("a", child.getAString());
391    assertEquals("b", child.getBString());
392    commitTxn();
393  }
394
395  private void testFetchGrandchild(Class<? extends com.google.appengine.datanucleus.test.jdo.SubclassesJDO.Grandchild> grandchildClass) {
396    Entity e = new Entity(kindForClass(grandchildClass));
397    e.setProperty("aString", "a");
398    e.setProperty("bString", "b");
399    e.setProperty("cString", "c");
400    ds.put(e);
401
402    beginTxn();
403    com.google.appengine.datanucleus.test.jdo.SubclassesJDO.Grandchild
404        grandchild = pm.getObjectById(grandchildClass, e.getKey());
405    assertEquals(grandchildClass, grandchild.getClass());
406    assertEquals("a", grandchild.getAString());
407    assertEquals("b", grandchild.getBString());
408    assertEquals("c", grandchild.getCString());
409    commitTxn();
410  }
411
412  private void testQueryParent(Class<? extends Parent> parentClass) {
413    Entity e = new Entity(kindForClass(parentClass));
414    e.setProperty("aString", "z8");
415    ds.put(e);
416
417    e = new Entity(kindForClass(parentClass));
418    e.setProperty("aString", "z9");
419    ds.put(e);
420
421    beginTxn();
422    Parent parent = ((List<Parent>) pm.newQuery(
423        "select from " + parentClass.getName() + " where aString == 'z8'").execute()).get(0);
424    assertEquals(parentClass, parent.getClass());
425    assertEquals("z8", parent.getAString());
426    commitTxn();
427
428    beginTxn();
429    List<Parent> parents = ((List<Parent>) pm.newQuery(
430        "select from " + parentClass.getName() + " where aString >= 'z8' order by aString desc").execute());
431    assertEquals(2, parents.size());
432    assertEquals("z9", parents.get(0).getAString());
433    assertEquals("z8", parents.get(1).getAString());
434    commitTxn();
435
436    beginTxn();
437    String aString = ((List<String>) pm.newQuery(
438        "select aString from " + parentClass.getName() + " where aString == 'z8'").execute()).get(0);
439    assertEquals("z8", aString);
440    commitTxn();
441  }
442
443  private void testQueryChild(Class<? extends SubclassesJDO.Child> childClass) {
444    Entity e1 = new Entity(kindForClass(childClass));
445    e1.setProperty("aString", "a2");
446    e1.setProperty("bString", "b2");
447    ds.put(e1);
448
449    Entity e2 = new Entity(kindForClass(childClass));
450    e2.setProperty("aString", "a2");
451    e2.setProperty("bString", "b3");
452    ds.put(e2);
453
454    Entity e3 = new Entity(kindForClass(childClass));
455    e3.setProperty("aString", "a2");
456    e3.setProperty("bString", "b3");
457    ds.put(e3);
458
459    beginTxn();
460
461    SubclassesJDO.Child child = ((List<SubclassesJDO.Child>) pm.newQuery(
462        "select from " + childClass.getName() + " where aString == 'a2'").execute()).get(0);
463    assertEquals(childClass, child.getClass());
464    assertEquals("a2", child.getAString());
465    assertEquals("b2", child.getBString());
466
467    child = ((List<SubclassesJDO.Child>) pm.newQuery(
468        "select from " + childClass.getName() + " where bString == 'b2'").execute()).get(0);
469    assertEquals(childClass, child.getClass());
470    assertEquals("a2", child.getAString());
471    assertEquals("b2", child.getBString());
472
473    List<SubclassesJDO.Child> kids = ((List<SubclassesJDO.Child>) pm.newQuery(
474        "select from " + childClass.getName() + " where aString == 'a2' order by bString desc").execute());
475    assertEquals(3, kids.size());
476    assertEquals(e2.getKey().getId(), kids.get(0).getId().longValue());
477    assertEquals(e3.getKey().getId(), kids.get(1).getId().longValue());
478    assertEquals(e1.getKey().getId(), kids.get(2).getId().longValue());
479
480    kids = ((List<SubclassesJDO.Child>) pm.newQuery("select from " + childClass.getName() + " where aString == 'a2' order by aString desc").execute());
481    assertEquals(3, kids.size());
482    assertEquals(e1.getKey().getId(), kids.get(0).getId().longValue());
483    assertEquals(e2.getKey().getId(), kids.get(1).getId().longValue());
484    assertEquals(e3.getKey().getId(), kids.get(2).getId().longValue());
485
486    Object[] result = ((List<Object[]>) pm.newQuery("select bString, aString from " + childClass.getName() + " where bString == 'b2'").execute()).get(0);
487    assertEquals(2, result.length);
488    assertEquals("b2", result[0]);
489    assertEquals("a2", result[1]);
490
491    commitTxn();
492  }
493
494  private void testQueryGrandchild(Class<? extends com.google.appengine.datanucleus.test.jdo.SubclassesJDO.Grandchild> grandchildClass) {
495    Entity e1 = new Entity(kindForClass(grandchildClass));
496    e1.setProperty("aString", "a2");
497    e1.setProperty("bString", "b1");
498    e1.setProperty("cString", "c2");
499    ds.put(e1);
500
501    Entity e2 = new Entity(kindForClass(grandchildClass));
502    e2.setProperty("aString", "a2");
503    e2.setProperty("bString", "b3");
504    e2.setProperty("cString", "c3");
505    ds.put(e2);
506
507    Entity e3 = new Entity(kindForClass(grandchildClass));
508    e3.setProperty("aString", "a2");
509    e3.setProperty("bString", "b2");
510    e3.setProperty("cString", "c3");
511    ds.put(e3);
512
513    beginTxn();
514    Grandchild grandchild = ((List<Grandchild>) pm.newQuery(
515        "select from " + grandchildClass.getName() + " where aString == 'a2'").execute()).get(0);
516    assertEquals(grandchildClass, grandchild.getClass());
517    assertEquals("a2", grandchild.getAString());
518    assertEquals("b1", grandchild.getBString());
519    assertEquals("c2", grandchild.getCString());
520
521    grandchild = ((List<Grandchild>) pm.newQuery(
522        "select from " + grandchildClass.getName() + " where bString == 'b2'").execute()).get(0);
523    assertEquals(grandchildClass, grandchild.getClass());
524    assertEquals("a2", grandchild.getAString());
525    assertEquals("b2", grandchild.getBString());
526    assertEquals("c3", grandchild.getCString());
527
528    grandchild = ((List<Grandchild>) pm.newQuery(
529        "select from " + grandchildClass.getName() + " where cString == 'c2'").execute()).get(0);
530    assertEquals(grandchildClass, grandchild.getClass());
531    assertEquals("a2", grandchild.getAString());
532    assertEquals("b1", grandchild.getBString());
533    assertEquals("c2", grandchild.getCString());
534
535    List<Grandchild> grandkids = ((List<Grandchild>) pm.newQuery(
536        "select from " + grandchildClass.getName() + " where aString == 'a2' order by bString desc").execute());
537    assertEquals(3, grandkids.size());
538    assertEquals(e2.getKey().getId(), grandkids.get(0).getId().longValue());
539    assertEquals(e3.getKey().getId(), grandkids.get(1).getId().longValue());
540    assertEquals(e1.getKey().getId(), grandkids.get(2).getId().longValue());
541
542    grandkids = ((List<Grandchild>) pm.newQuery(
543        "select from " + grandchildClass.getName() + " where aString == 'a2' order by aString desc").execute());
544    assertEquals(3, grandkids.size());
545    assertEquals(e1.getKey().getId(), grandkids.get(0).getId().longValue());
546    assertEquals(e2.getKey().getId(), grandkids.get(1).getId().longValue());
547    assertEquals(e3.getKey().getId(), grandkids.get(2).getId().longValue());
548
549    grandkids = ((List<Grandchild>) pm.newQuery(
550        "select from " + grandchildClass.getName() + " where aString == 'a2' order by cString desc").execute());
551    assertEquals(3, grandkids.size());
552    assertEquals(e2.getKey().getId(), grandkids.get(0).getId().longValue());
553    assertEquals(e3.getKey().getId(), grandkids.get(1).getId().longValue());
554    assertEquals(e1.getKey().getId(), grandkids.get(2).getId().longValue());
555
556    Object[] result = ((List<Object[]>) pm.newQuery(
557        "select bString, aString, cString from " + grandchildClass.getName() + " where cString == 'c2'").execute()).get(0);
558    assertEquals(3, result.length);
559    assertEquals("b1", result[0]);
560    assertEquals("a2", result[1]);
561    assertEquals("c2", result[2]);
562
563    commitTxn();
564  }
565
566  private void testDeleteParent(Class<? extends Parent> parentClass) {
567    Entity e = new Entity(kindForClass(parentClass));
568    e.setProperty("aString", "a");
569    ds.put(e);
570
571    beginTxn();
572    Parent parent = pm.getObjectById(parentClass, e.getKey());
573    pm.deletePersistent(parent);
574    commitTxn();
575    try {
576      ds.get(e.getKey());
577      fail("expected exception");
578    } catch (EntityNotFoundException e1) {
579      // good
580    }
581  }
582
583  private void testDeleteChild(Class<? extends SubclassesJDO.Child> childClass) {
584    Entity e = new Entity(kindForClass(childClass));
585    e.setProperty("aString", "a");
586    e.setProperty("bString", "b");
587    ds.put(e);
588
589    beginTxn();
590    SubclassesJDO.Child child = pm.getObjectById(childClass, e.getKey());
591    pm.deletePersistent(child);
592    commitTxn();
593    try {
594      ds.get(e.getKey());
595      fail("expected exception");
596    } catch (EntityNotFoundException e1) {
597      // good
598    }
599  }
600
601  private void testDeleteGrandchild(Class<? extends com.google.appengine.datanucleus.test.jdo.SubclassesJDO.Grandchild> grandchildClass) {
602    Entity e = new Entity(kindForClass(grandchildClass));
603    e.setProperty("aString", "a");
604    e.setProperty("bString", "b");
605    e.setProperty("cString", "c");
606    ds.put(e);
607
608    beginTxn();
609    SubclassesJDO.Child child = pm.getObjectById(grandchildClass, e.getKey());
610    pm.deletePersistent(child);
611    commitTxn();
612    try {
613      ds.get(e.getKey());
614      fail("expected exception");
615    } catch (EntityNotFoundException e1) {
616      // good
617    }
618  }
619
620  private void testUpdateParent(Class<? extends Parent> parentClass) throws Exception {
621    Entity e = new Entity(kindForClass(parentClass));
622    e.setProperty("aString", "a");
623    ds.put(e);
624
625    beginTxn();
626    Parent parent = pm.getObjectById(parentClass, e.getKey());
627    parent.setAString("not a");
628    commitTxn();
629    e = ds.get(e.getKey());
630    assertEquals("not a", e.getProperty("aString"));
631  }
632
633  private void testUpdateChild(Class<? extends SubclassesJDO.Child> childClass) throws Exception {
634    Entity e = new Entity(kindForClass(childClass));
635    e.setProperty("aString", "a");
636    e.setProperty("bString", "b");
637    ds.put(e);
638
639    beginTxn();
640    SubclassesJDO.Child child = pm.getObjectById(childClass, e.getKey());
641    child.setAString("not a");
642    child.setBString("not b");
643    commitTxn();
644    e = ds.get(e.getKey());
645    assertEquals("not a", e.getProperty("aString"));
646    assertEquals("not b", e.getProperty("bString"));
647  }
648
649  private void testUpdateGrandchild(Class<? extends com.google.appengine.datanucleus.test.jdo.SubclassesJDO.Grandchild> grandchildClass) throws Exception {
650    Entity e = new Entity(kindForClass(grandchildClass));
651    e.setProperty("aString", "a");
652    e.setProperty("bString", "b");
653    ds.put(e);
654
655    beginTxn();
656    com.google.appengine.datanucleus.test.jdo.SubclassesJDO.Grandchild
657        grandchild = pm.getObjectById(grandchildClass, e.getKey());
658    grandchild.setAString("not a");
659    grandchild.setBString("not b");
660    grandchild.setCString("not c");
661    commitTxn();
662    e = ds.get(e.getKey());
663    assertEquals("not a", e.getProperty("aString"));
664    assertEquals("not b", e.getProperty("bString"));
665    assertEquals("not c", e.getProperty("cString"));
666  }
667
668  private void testGrandchild(com.google.appengine.datanucleus.test.jdo.SubclassesJDO.Grandchild grandchild) throws Exception {
669    testInsertGrandchild(grandchild);
670    testUpdateGrandchild(grandchild.getClass());
671    testDeleteGrandchild(grandchild.getClass());
672    testFetchGrandchild(grandchild.getClass());
673    testQueryGrandchild(grandchild.getClass());
674  }
675
676  private void testChild(SubclassesJDO.Child child) throws Exception {
677    testInsertChild(child);
678    testUpdateChild(child.getClass());
679    testDeleteChild(child.getClass());
680    testFetchChild(child.getClass());
681    testQueryChild(child.getClass());
682  }
683
684  private void testParent(Parent parent) throws Exception {
685    testInsertParent(parent);
686    testUpdateParent(parent.getClass());
687    testDeleteParent(parent.getClass());
688    testFetchParent(parent.getClass());
689    testQueryParent(parent.getClass());
690  }
691
692}