/*
* Copyright (c) 2011-2015 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.spotify.asyncdatastoreclient;
import com.google.common.base.Throwables;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
@Category(IntegrationTest.class)
public class TransactionTest extends DatastoreTest {
@Test
public void testInsert() throws Exception {
final TransactionResult txn = datastore.transaction();
final Insert insert = QueryBuilder.insert("employee")
.value("fullname", "Fred Blinge")
.value("age", 40, false);
final MutationResult insertResult = datastore.execute(insert, txn);
final KeyQuery get = QueryBuilder.query(insertResult.getInsertKey());
final QueryResult getResult = datastore.execute(get);
assertEquals("Fred Blinge", getResult.getEntity().getString("fullname"));
assertEquals(40, getResult.getEntity().getInteger("age").intValue());
}
@Test
public void testInsertAsync() throws Exception {
final ListenableFuture<TransactionResult> txn = datastore.transactionAsync();
final Insert insert = QueryBuilder.insert("employee")
.value("fullname", "Fred Blinge")
.value("age", 40, false);
final ListenableFuture<MutationResult> insertResult = datastore.executeAsync(insert, txn);
final ListenableFuture<QueryResult> getResult = Futures.transform(insertResult, (MutationResult mutationResult) -> {
final KeyQuery get = QueryBuilder.query(mutationResult.getInsertKey());
return datastore.executeAsync(get);
});
Futures.addCallback(getResult, new FutureCallback<QueryResult>() {
@Override
public void onSuccess(final QueryResult result) {
assertEquals("Fred Blinge", result.getEntity().getString("fullname"));
assertEquals(40, result.getEntity().getInteger("age").intValue());
}
@Override
public void onFailure(final Throwable throwable) {
fail(Throwables.getRootCause(throwable).getMessage());
}
});
}
@Test
public void testGetThenInsert() throws Exception {
final TransactionResult txn = datastore.transaction();
final KeyQuery get = QueryBuilder.query("employee", 1234567L);
final QueryResult getResult = datastore.execute(get, txn);
assertEquals(0, getResult.getAll().size());
final Insert insert = QueryBuilder.insert("employee", 1234567L)
.value("fullname", "Fred Blinge")
.value("age", 40, false);
final MutationResult insertResult = datastore.execute(insert, txn);
assertTrue(insertResult.getIndexUpdates() > 0);
}
@Test
public void testTransactionExpired() throws Exception {
final TransactionResult txn = datastore.transaction();
final Insert insertFirst = QueryBuilder.insert("employee")
.value("fullname", "Fred Blinge")
.value("age", 40, false);
datastore.execute(insertFirst, txn);
final Insert insertSecond = QueryBuilder.insert("employee")
.value("fullname", "Fred Blinge")
.value("age", 40, false);
try {
datastore.execute(insertSecond, txn);
fail("Expected DatastoreException exception.");
} catch (final DatastoreException e) {
assertEquals(400, e.getStatusCode().intValue()); // bad request
}
}
@Test
public void testTransactionWriteConflict() throws Exception {
final Insert insert = QueryBuilder.insert("employee", 1234567L)
.value("fullname", "Fred Blinge")
.value("age", 40, false);
datastore.execute(insert);
final TransactionResult txn = datastore.transaction();
final KeyQuery get = QueryBuilder.query("employee", 1234567L);
final QueryResult getResult = datastore.execute(get, txn);
assertNotNull(getResult.getEntity());
final Update update = QueryBuilder.update("employee", 1234567L)
.value("age", 41, false);
datastore.execute(update); // update outside transaction
try {
datastore.execute(update, txn); // update inside transaction
fail("Expected DatastoreException exception.");
} catch (final DatastoreException e) {
assertEquals(409, e.getStatusCode().intValue()); // conflict
}
}
@Test
public void testTransactionRead() throws Exception {
final Insert insert = QueryBuilder.insert("employee", 1234567L)
.value("fullname", "Fred Blinge")
.value("age", 40, false);
datastore.execute(insert);
final TransactionResult txn = datastore.transaction();
final KeyQuery get = QueryBuilder.query("employee", 1234567L);
final QueryResult getResult1 = datastore.execute(get, txn);
assertEquals(40, getResult1.getEntity().getInteger("age").intValue());
final Update update = QueryBuilder.update("employee", 1234567L)
.value("age", 41, false);
datastore.execute(update); // update outside transaction
final QueryResult getResult2 = datastore.execute(get, txn); // read inside transaction
assertEquals(40, getResult2.getEntity().getInteger("age").intValue());
}
@Test
public void testInsertBatchInTransaction() throws Exception {
final TransactionResult txn = datastore.transaction();
final Key parent = Key.builder("parent", "root").build();
final Insert insert1 = QueryBuilder.insert(Key.builder("employee", parent).build())
.value("fullname", "Jack Spratt")
.value("age", 21, false);
final Insert insert2 = QueryBuilder.insert(Key.builder("employee", parent).build())
.value("fullname", "Fred Blinge")
.value("age", 40, false);
final Insert insert3 = QueryBuilder.insert(Key.builder("employee", parent).build())
.value("fullname", "Harry Ramsdens")
.value("age", 50, false);
final Batch batch = QueryBuilder.batch()
.add(insert1)
.add(insert2)
.add(insert3);
final MutationResult result = datastore.execute(batch, txn);
assertFalse(result.getInsertKeys().isEmpty());
final Query getAll = QueryBuilder.query()
.kindOf("employee")
.filterBy(QueryBuilder.ancestor(parent))
.orderBy(QueryBuilder.asc("fullname"));
final List<Entity> entities = datastore.execute(getAll).getAll();
assertEquals(3, entities.size());
assertEquals("Fred Blinge", entities.get(0).getString("fullname"));
assertEquals("Harry Ramsdens", entities.get(1).getString("fullname"));
assertEquals("Jack Spratt", entities.get(2).getString("fullname"));
}
@Test
public void testQueryInTransaction() throws Exception {
final Key parent = Key.builder("parent", "root").build();
final Insert insert1 = QueryBuilder.insert(Key.builder("employee", parent).build())
.value("fullname", "Jack Spratt")
.value("age", 21, false);
final Insert insert2 = QueryBuilder.insert(Key.builder("employee", parent).build())
.value("fullname", "Fred Blinge")
.value("age", 40, false);
final Insert insert3 = QueryBuilder.insert(Key.builder("employee", parent).build())
.value("fullname", "Harry Ramsdens")
.value("age", 50, false);
final Batch batch = QueryBuilder.batch()
.add(insert1)
.add(insert2)
.add(insert3);
final MutationResult result = datastore.execute(batch);
assertFalse(result.getInsertKeys().isEmpty());
final TransactionResult txn = datastore.transaction();
final Query getAll = QueryBuilder.query()
.kindOf("employee")
.filterBy(QueryBuilder.ancestor(parent))
.orderBy(QueryBuilder.asc("fullname"));
final List<Entity> entities = datastore.execute(getAll, txn).getAll();
assertEquals(3, entities.size());
assertEquals("Fred Blinge", entities.get(0).getString("fullname"));
assertEquals("Harry Ramsdens", entities.get(1).getString("fullname"));
assertEquals("Jack Spratt", entities.get(2).getString("fullname"));
datastore.commit(txn);
}
}