diff options
Diffstat (limited to 'vespajlib/src/test/java/com/yahoo/transaction/NestedTransactionTestCase.java')
-rw-r--r-- | vespajlib/src/test/java/com/yahoo/transaction/NestedTransactionTestCase.java | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/vespajlib/src/test/java/com/yahoo/transaction/NestedTransactionTestCase.java b/vespajlib/src/test/java/com/yahoo/transaction/NestedTransactionTestCase.java new file mode 100644 index 00000000000..d75daa506b4 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/transaction/NestedTransactionTestCase.java @@ -0,0 +1,181 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.transaction; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author bratseth + */ +public class NestedTransactionTestCase { + + @Test + public void testNestedTransaction() { + NestedTransaction t = new NestedTransaction(); + t.add(new TransactionTypeB("B1"), TransactionTypeC.class); + t.add(new TransactionTypeC("C1")); + t.add(new TransactionTypeA("A1"), TransactionTypeB.class); + t.add(new TransactionTypeA("A2")); + t.add(new TransactionTypeC("C2")); + + // Add two tasks to run after commit + MutableInteger tasksRun = new MutableInteger(); + t.onCommitted(() -> { tasksRun.value++; }); + t.onCommitted(() -> { tasksRun.value++; }); + + assertEquals(3, t.transactions().size()); + assertEquals(TransactionTypeA.class, t.transactions().get(0).getClass()); + assertEquals(TransactionTypeB.class, t.transactions().get(1).getClass()); + assertEquals(TransactionTypeC.class, t.transactions().get(2).getClass()); + + assertEquals("A1", ((MockOperation)t.transactions().get(0).operations().get(0)).name); + assertEquals("A2", ((MockOperation)t.transactions().get(0).operations().get(1)).name); + assertEquals("B1", ((MockOperation)t.transactions().get(1).operations().get(0)).name); + assertEquals("C1", ((MockOperation)t.transactions().get(2).operations().get(0)).name); + assertEquals("C2", ((MockOperation)t.transactions().get(2).operations().get(1)).name); + + t.commit(); + assertTrue(((MockTransaction)t.transactions().get(0)).committed); + assertTrue(((MockTransaction)t.transactions().get(1)).committed); + assertTrue(((MockTransaction)t.transactions().get(2)).committed); + assertEquals("After commit tasks are run", 2, tasksRun.value); + } + + @Test + public void testNestedTransactionFailingOnCommit() { + NestedTransaction t = new NestedTransaction(); + t.add(new TransactionTypeC("C1")); + t.add(new TransactionTypeA("A1"), TransactionTypeB.class, FailAtCommitTransactionType.class); + t.add(new TransactionTypeA("A2")); + t.add(new FailAtCommitTransactionType("Fail"), TransactionTypeC.class); + t.add(new TransactionTypeC("C2")); + t.add(new TransactionTypeB("B1"), TransactionTypeC.class, FailAtCommitTransactionType.class); + + // Add task to run after commit + MutableInteger tasksRun = new MutableInteger(); + t.onCommitted(() -> { + tasksRun.value++; + }); + + assertEquals(4, t.transactions().size()); + assertEquals(TransactionTypeA.class, t.transactions().get(0).getClass()); + assertEquals(TransactionTypeB.class, t.transactions().get(1).getClass()); + assertEquals(FailAtCommitTransactionType.class, t.transactions().get(2).getClass()); + assertEquals(TransactionTypeC.class, t.transactions().get(3).getClass()); + + try { t.commit(); } catch (IllegalStateException expected) { } + assertTrue(((MockTransaction)t.transactions().get(0)).rolledback); + assertTrue(((MockTransaction)t.transactions().get(1)).rolledback); + assertFalse(((MockTransaction) t.transactions().get(2)).committed); + assertEquals("After commit tasks are not run", 0, tasksRun.value); + } + + @Test + public void testConflictingOrdering() { + NestedTransaction t = new NestedTransaction(); + t.add(new TransactionTypeA("A1"), TransactionTypeB.class); + t.add(new TransactionTypeB("B1"), TransactionTypeC.class); + t.add(new TransactionTypeC("C1"), TransactionTypeA.class); + try { + t.commit(); + fail("Expected exception"); + } + catch (IllegalStateException expected) { + } + } + + private static class TransactionTypeA extends MockTransaction { + public TransactionTypeA(String name) { super(name); } + } + + private static class TransactionTypeB extends MockTransaction { + public TransactionTypeB(String name) { super(name); } + } + + private static class TransactionTypeC extends MockTransaction { + public TransactionTypeC(String name) { super(name); } + } + + private static class FailAtCommitTransactionType extends MockTransaction { + public FailAtCommitTransactionType(String name) { super(name); } + @Override + public void commit() { + throw new RuntimeException(); + } + } + + private static class MockTransaction implements Transaction { + + public boolean prepared = false, committed = false, rolledback = false; + private List<Operation> operations = new ArrayList<>(); + + public MockTransaction(String name) { + operations.add(new MockOperation(name)); + } + + @Override + public Transaction add(Operation operation) { + operations.add(operation); + return this; + } + + @Override + public Transaction add(List<Operation> operation) { + operations.addAll(operation); + return this; + } + + @Override + public List<Operation> operations() { + return operations; + } + + @Override + public void prepare() { + prepared = true; + } + + @Override + public void commit() { + if ( ! prepared) + throw new IllegalStateException("Commit before prepare"); + committed = true; + } + + @Override + public void rollbackOrLog() { + if ( ! committed) + throw new IllegalStateException("Rollback before commit"); + rolledback = true; + } + + @Override + public void close() { + } + + } + + private static class MockOperation implements Transaction.Operation { + + public String name; + + public MockOperation(String name) { + this.name = name; + } + + } + + private static class MutableInteger { + + public int value = 0; + + } + +} |