1 package com.atlassian.sal.core.rdbms;
2
3 import com.atlassian.sal.api.rdbms.RdbmsException;
4 import org.hamcrest.Description;
5 import org.hamcrest.Matcher;
6 import org.hamcrest.TypeSafeMatcher;
7 import org.junit.Test;
8 import org.junit.runner.RunWith;
9 import org.junit.runners.Parameterized;
10
11 import java.sql.SQLException;
12 import java.util.Arrays;
13 import java.util.Collection;
14
15 import static org.hamcrest.Matchers.nullValue;
16 import static org.hamcrest.core.Is.is;
17 import static org.hamcrest.core.Is.isA;
18 import static org.junit.Assert.assertThat;
19 import static org.mockito.Matchers.any;
20 import static org.mockito.Mockito.*;
21
22 @RunWith (Parameterized.class)
23 public class TestDefaultTransactionalExecutorExceptions extends TestDefaultTransactionalExecutorBase
24 {
25 @Parameterized.Parameters(name = "{index}: throwing {0}")
26 public static Collection data () {
27 return Arrays.asList(new Object[][] {
28 { new SQLException("horrible commit exception") },
29 { new LinkageError("horrible linkage error") },
30 });
31 }
32 @Parameterized.Parameter(0)
33 public Throwable exception;
34
35 @Test
36 public void executeCommitFails() throws SQLException
37 {
38 doThrow(exception).when(connection).commit();
39
40 expectedException.expect(RdbmsException.class);
41 expectedException.expectCause(isA(exception.getClass()));
42
43 defaultTransactionalExecutor.executeInternal(connection, callback);
44 assertThat(wrappedConnection.connection, nullValue());
45
46 verify(callback).execute(any(WrappedConnection.class));
47 verify(connection).commit();
48 verify(connection, never()).rollback();
49 }
50
51 @Test
52 public void executeRollbackFails() throws SQLException
53 {
54 callbackThrows = new TestDefaultTransactionalExecutorBase.CallbackException("epic fail");
55
56 doThrow(exception).when(connection).rollback();
57
58 expectedException.expect(CallbackException.class);
59 expectedException.expectMessage("epic fail");
60 expectedException.expect(new SuppressedMatches(is(exception)));
61
62 defaultTransactionalExecutor.executeInternal(connection, callback);
63 assertThat(wrappedConnection.connection, nullValue());
64
65 verify(callback).execute(any(WrappedConnection.class));
66 verify(connection, never()).commit();
67 verify(connection).rollback();
68 }
69
70 private static class SuppressedMatches<T extends Throwable> extends TypeSafeMatcher<T> {
71 private Matcher<T> expectedSuppressed;
72 public SuppressedMatches(Matcher<T> expectedSuppressed)
73 {
74 this.expectedSuppressed = expectedSuppressed;
75 }
76
77 @Override
78 protected void describeMismatchSafely(final T item, final Description mismatchDescription)
79 {
80 mismatchDescription.appendText("was not found in ").appendValue(item.getSuppressed());
81 }
82
83 @Override
84 public void describeTo(final Description description)
85 {
86 description.appendText("a suppressed exception matching(");
87 expectedSuppressed.describeTo(description);
88 description.appendText(")");
89 }
90
91 @Override
92 public boolean matchesSafely(final Throwable t)
93 {
94 for (Throwable s: t.getSuppressed())
95 {
96 if (expectedSuppressed.matches(s))
97 {
98 return true;
99 }
100 }
101
102 return false;
103 }
104 }
105 }