Skip to content

Commit 0dbcf03

Browse files
tswastlesv
authored andcommitted
1 parent 01ecbef commit 0dbcf03

File tree

1 file changed

+309
-0
lines changed

1 file changed

+309
-0
lines changed
Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
/*
2+
* Copyright 2016 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.appengine;
18+
19+
import static com.google.common.truth.Truth.assertThat;
20+
import static org.junit.Assert.fail;
21+
22+
import com.google.appengine.api.datastore.DatastoreService;
23+
import com.google.appengine.api.datastore.DatastoreServiceFactory;
24+
import com.google.appengine.api.datastore.Entity;
25+
import com.google.appengine.api.datastore.EntityNotFoundException;
26+
import com.google.appengine.api.datastore.FetchOptions;
27+
import com.google.appengine.api.datastore.Key;
28+
import com.google.appengine.api.datastore.KeyFactory;
29+
import com.google.appengine.api.datastore.PreparedQuery;
30+
import com.google.appengine.api.datastore.Query;
31+
import com.google.appengine.api.datastore.Transaction;
32+
import com.google.appengine.api.datastore.TransactionOptions;
33+
import com.google.appengine.api.taskqueue.Queue;
34+
import com.google.appengine.api.taskqueue.QueueFactory;
35+
import com.google.appengine.api.taskqueue.TaskOptions;
36+
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
37+
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
38+
import org.junit.After;
39+
import org.junit.Before;
40+
import org.junit.Test;
41+
import org.junit.runner.RunWith;
42+
import org.junit.runners.JUnit4;
43+
44+
import java.util.ConcurrentModificationException;
45+
import java.util.Date;
46+
import java.util.List;
47+
48+
/**
49+
* Unit tests to demonstrate App Engine Datastore transactions.
50+
*/
51+
@RunWith(JUnit4.class)
52+
public class TransactionsTest {
53+
54+
private final LocalServiceTestHelper helper =
55+
new LocalServiceTestHelper(
56+
// Use High Rep job policy to allow cross group transactions in tests.
57+
new LocalDatastoreServiceTestConfig().setApplyAllHighRepJobPolicy());
58+
59+
private DatastoreService datastore;
60+
61+
@Before
62+
public void setUp() {
63+
helper.setUp();
64+
datastore = DatastoreServiceFactory.getDatastoreService();
65+
}
66+
67+
@After
68+
public void tearDown() {
69+
// Clean up any dangling transactions.
70+
Transaction txn = datastore.getCurrentTransaction(null);
71+
if (txn != null && txn.isActive()) {
72+
txn.rollback();
73+
}
74+
helper.tearDown();
75+
}
76+
77+
@Test
78+
public void usingTransactions() throws Exception {
79+
Entity joe = new Entity("Employee", "Joe");
80+
datastore.put(joe);
81+
82+
// [START using_transactions]
83+
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
84+
Transaction txn = datastore.beginTransaction();
85+
try {
86+
Key employeeKey = KeyFactory.createKey("Employee", "Joe");
87+
Entity employee = datastore.get(employeeKey);
88+
employee.setProperty("vacationDays", 10);
89+
90+
datastore.put(txn, employee);
91+
92+
txn.commit();
93+
} finally {
94+
if (txn.isActive()) {
95+
txn.rollback();
96+
}
97+
}
98+
// [END using_transactions]
99+
}
100+
101+
@Test
102+
public void entityGroups() throws Exception {
103+
try {
104+
// [START entity_groups]
105+
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
106+
Entity person = new Entity("Person", "tom");
107+
datastore.put(person);
108+
109+
// Transactions on root entities
110+
Transaction txn = datastore.beginTransaction();
111+
112+
Entity tom = datastore.get(person.getKey());
113+
tom.setProperty("age", 40);
114+
datastore.put(txn, tom);
115+
txn.commit();
116+
117+
// Transactions on child entities
118+
txn = datastore.beginTransaction();
119+
tom = datastore.get(person.getKey());
120+
Entity photo = new Entity("Photo", tom.getKey());
121+
122+
// Create a Photo that is a child of the Person entity named "tom"
123+
photo.setProperty("photoUrl", "http://domain.com/path/to/photo.jpg");
124+
datastore.put(txn, photo);
125+
txn.commit();
126+
127+
// Transactions on entities in different entity groups
128+
txn = datastore.beginTransaction();
129+
tom = datastore.get(person.getKey());
130+
Entity photoNotAChild = new Entity("Photo");
131+
photoNotAChild.setProperty("photoUrl", "http://domain.com/path/to/photo.jpg");
132+
datastore.put(txn, photoNotAChild);
133+
134+
// Throws IllegalArgumentException because the Person entity
135+
// and the Photo entity belong to different entity groups.
136+
txn.commit();
137+
// [END entity_groups]
138+
fail("Expected IllegalArgumentException");
139+
} catch (IllegalArgumentException expected) {
140+
// We expect to get an exception that complains that we don't have a XG-transaction.
141+
}
142+
}
143+
144+
@Test
145+
public void creatingAnEntityInASpecificEntityGroup() throws Exception {
146+
String boardName = "my-message-board";
147+
148+
// [START creating_an_entity_in_a_specific_entity_group]
149+
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
150+
151+
String messageTitle = "Some Title";
152+
String messageText = "Some message.";
153+
Date postDate = new Date();
154+
155+
Transaction txn = datastore.beginTransaction();
156+
157+
Key messageBoardKey = KeyFactory.createKey("MessageBoard", boardName);
158+
159+
Entity message = new Entity("Message", messageBoardKey);
160+
message.setProperty("message_title", messageTitle);
161+
message.setProperty("message_text", messageText);
162+
message.setProperty("post_date", postDate);
163+
datastore.put(txn, message);
164+
165+
txn.commit();
166+
// [END creating_an_entity_in_a_specific_entity_group]
167+
}
168+
169+
@Test
170+
public void crossGroupTransactions() throws Exception {
171+
// [START cross-group_XG_transactions_using_the_Java_low-level_API]
172+
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
173+
TransactionOptions options = TransactionOptions.Builder.withXG(true);
174+
Transaction txn = datastore.beginTransaction(options);
175+
176+
Entity a = new Entity("A");
177+
a.setProperty("a", 22);
178+
datastore.put(txn, a);
179+
180+
Entity b = new Entity("B");
181+
b.setProperty("b", 11);
182+
datastore.put(txn, b);
183+
184+
txn.commit();
185+
// [END cross-group_XG_transactions_using_the_Java_low-level_API]
186+
}
187+
188+
@Test
189+
public void usesForTransactions_relativeUpdates() throws Exception {
190+
String boardName = "my-message-board";
191+
Entity b = new Entity("MessageBoard", boardName);
192+
b.setProperty("count", 41);
193+
datastore.put(b);
194+
195+
// [START uses_for_transactions_1]
196+
int retries = 3;
197+
while (true) {
198+
Transaction txn = datastore.beginTransaction();
199+
try {
200+
Key boardKey = KeyFactory.createKey("MessageBoard", boardName);
201+
Entity messageBoard = datastore.get(boardKey);
202+
203+
long count = (Long) messageBoard.getProperty("count");
204+
++count;
205+
messageBoard.setProperty("count", count);
206+
datastore.put(txn, messageBoard);
207+
208+
txn.commit();
209+
break;
210+
} catch (ConcurrentModificationException e) {
211+
if (retries == 0) {
212+
throw e;
213+
}
214+
// Allow retry to occur
215+
--retries;
216+
} finally {
217+
if (txn.isActive()) {
218+
txn.rollback();
219+
}
220+
}
221+
}
222+
// [END uses_for_transactions_1]
223+
224+
b = datastore.get(KeyFactory.createKey("MessageBoard", boardName));
225+
assertThat((long) b.getProperty("count")).named("board.count").isEqualTo(42L);
226+
}
227+
228+
private Entity fetchOrCreate(String boardName) {
229+
// [START uses_for_transactions_2]
230+
Transaction txn = datastore.beginTransaction();
231+
Entity messageBoard;
232+
Key boardKey;
233+
try {
234+
boardKey = KeyFactory.createKey("MessageBoard", boardName);
235+
messageBoard = datastore.get(boardKey);
236+
} catch (EntityNotFoundException e) {
237+
messageBoard = new Entity("MessageBoard", boardName);
238+
messageBoard.setProperty("count", 0L);
239+
boardKey = datastore.put(txn, messageBoard);
240+
}
241+
txn.commit();
242+
// [END uses_for_transactions_2]
243+
244+
return messageBoard;
245+
}
246+
247+
@Test
248+
public void usesForTransactions_fetchOrCreate_fetchesExisting() throws Exception {
249+
Entity b = new Entity("MessageBoard", "my-message-board");
250+
b.setProperty("count", 7);
251+
datastore.put(b);
252+
253+
Entity board = fetchOrCreate("my-message-board");
254+
255+
assertThat((long) board.getProperty("count")).named("board.count").isEqualTo(7L);
256+
}
257+
258+
@Test
259+
public void usesForTransactions_fetchOrCreate_createsNew() throws Exception {
260+
Entity board = fetchOrCreate("my-message-board");
261+
assertThat((long) board.getProperty("count")).named("board.count").isEqualTo(0L);
262+
}
263+
264+
@Test
265+
public void usesForTransactions_readSnapshot() throws Exception {
266+
String boardName = "my-message-board";
267+
Entity b = new Entity("MessageBoard", boardName);
268+
b.setProperty("count", 13);
269+
datastore.put(b);
270+
271+
// [START uses_for_transactions_3]
272+
DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
273+
274+
// Display information about a message board and its first 10 messages.
275+
Key boardKey = KeyFactory.createKey("MessageBoard", boardName);
276+
277+
Transaction txn = datastore.beginTransaction();
278+
279+
Entity messageBoard = datastore.get(boardKey);
280+
long count = (Long) messageBoard.getProperty("count");
281+
282+
Query q = new Query("Message", boardKey);
283+
284+
// This is an ancestor query.
285+
PreparedQuery pq = datastore.prepare(txn, q);
286+
List<Entity> messages = pq.asList(FetchOptions.Builder.withLimit(10));
287+
288+
txn.commit();
289+
// [END uses_for_transactions_3]
290+
291+
assertThat(count).named("board.count").isEqualTo(13L);
292+
}
293+
294+
@Test
295+
public void transactionalTaskEnqueuing() throws Exception {
296+
// [START transactional_task_enqueuing]
297+
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
298+
Queue queue = QueueFactory.getDefaultQueue();
299+
Transaction txn = datastore.beginTransaction();
300+
// ...
301+
302+
queue.add(TaskOptions.Builder.withUrl("/path/to/handler"));
303+
304+
// ...
305+
306+
txn.commit();
307+
// [END transactional_task_enqueuing]
308+
}
309+
}

0 commit comments

Comments
 (0)