From 5f7b99e8391220e3752c21271a7fff1dab81c6f5 Mon Sep 17 00:00:00 2001 From: sttk Date: Tue, 25 Aug 2026 08:59:04 +0900 Subject: [PATCH] test,refactor: added some test cases --- build.sh | 1 + .../github/sttk/sabi/TxnFailureReport.java | 48 +-- .../sttk/sabi/internal/DataSrcManager.java | 4 +- .../sabi/internal/AsyncGroupImplTest.java | 76 +++- .../sabi/internal/DataConnManagerTest.java | 329 ++++++++++++++++-- .../sttk/sabi/internal/DataHubInnerTest.java | 126 +++++-- .../sabi/internal/DataSrcManagerTest.java | 129 ++++++- 7 files changed, 614 insertions(+), 99 deletions(-) diff --git a/build.sh b/build.sh index e326905..a92320f 100755 --- a/build.sh +++ b/build.sh @@ -66,6 +66,7 @@ deploy() { if [[ "$#" == "0" ]]; then clean format + test jar javadoc native_test diff --git a/src/main/java/com/github/sttk/sabi/TxnFailureReport.java b/src/main/java/com/github/sttk/sabi/TxnFailureReport.java index 4c4101a..f4e5836 100644 --- a/src/main/java/com/github/sttk/sabi/TxnFailureReport.java +++ b/src/main/java/com/github/sttk/sabi/TxnFailureReport.java @@ -88,54 +88,42 @@ public TxnFailureRecovery recoveryForCommit() { switch (this.cause.state) { case NoneByUncommitted: switch (this.rollback.state) { - case NoneByNotRolledBack: - return TxnFailureRecovery.InvestigateBecauseImpossible; case NoneByRolledBack: return TxnFailureRecovery.RerunLogicAndCommit; case RollbackFailure: return TxnFailureRecovery.ResolveCauseAndInconsistency; - default: - return TxnFailureRecovery.InvestigateBecauseImpossible; } + break; case NoneByCommitted: switch (this.rollback.state) { case NoneByNotRolledBack: return TxnFailureRecovery.NoActionRequired; - default: - return TxnFailureRecovery.InvestigateBecauseImpossible; } + break; case LogicFailure: switch (this.rollback.state) { - case NoneByNotRolledBack: - return TxnFailureRecovery.InvestigateBecauseImpossible; case NoneByRolledBack: return TxnFailureRecovery.ResolveCauseThenRerunLogicAndCommit; case RollbackFailure: return TxnFailureRecovery.ResolveCauseAndInconsistency; - default: - return TxnFailureRecovery.InvestigateBecauseImpossible; } + break; case CommitFailure: switch (this.rollback.state) { - case NoneByNotRolledBack: - return TxnFailureRecovery.InvestigateBecauseImpossible; case NoneByRolledBack: return TxnFailureRecovery.ResolveCauseThenRerunLogicAndCommit; case RollbackFailure: return TxnFailureRecovery.ResolveCauseAndInconsistency; - default: - return TxnFailureRecovery.InvestigateBecauseImpossible; } + break; case PostCommitFailure: switch (this.rollback.state) { case NoneByNotRolledBack: return TxnFailureRecovery.ResolveCauseThenRerunPostCommit; - default: - return TxnFailureRecovery.InvestigateBecauseImpossible; } - default: - return TxnFailureRecovery.InvestigateBecauseImpossible; + break; } + return TxnFailureRecovery.InvestigateBecauseImpossible; } /** @@ -148,53 +136,41 @@ public TxnFailureRecovery recoveryForRollback() { switch (this.cause.state) { case NoneByUncommitted: switch (this.rollback.state) { - case NoneByNotRolledBack: - return TxnFailureRecovery.InvestigateBecauseImpossible; case NoneByRolledBack: return TxnFailureRecovery.NoActionRequired; case RollbackFailure: return TxnFailureRecovery.ResolveCauseAndInconsistency; - default: - return TxnFailureRecovery.InvestigateBecauseImpossible; } + break; case NoneByCommitted: switch (this.rollback.state) { case NoneByNotRolledBack: return TxnFailureRecovery.ManualRollbackRequired; - default: - return TxnFailureRecovery.InvestigateBecauseImpossible; } + break; case LogicFailure: switch (this.rollback.state) { - case NoneByNotRolledBack: - return TxnFailureRecovery.InvestigateBecauseImpossible; case NoneByRolledBack: return TxnFailureRecovery.NoActionRequired; case RollbackFailure: return TxnFailureRecovery.ResolveCauseAndInconsistency; - default: - return TxnFailureRecovery.InvestigateBecauseImpossible; } + break; case CommitFailure: switch (this.rollback.state) { - case NoneByNotRolledBack: - return TxnFailureRecovery.InvestigateBecauseImpossible; case NoneByRolledBack: return TxnFailureRecovery.NoActionRequired; case RollbackFailure: return TxnFailureRecovery.ResolveCauseAndInconsistency; - default: - return TxnFailureRecovery.InvestigateBecauseImpossible; } + break; case PostCommitFailure: switch (this.rollback.state) { case NoneByNotRolledBack: return TxnFailureRecovery.ManualRollbackRequired; - default: - return TxnFailureRecovery.InvestigateBecauseImpossible; } - default: - return TxnFailureRecovery.InvestigateBecauseImpossible; + break; } + return TxnFailureRecovery.InvestigateBecauseImpossible; } } diff --git a/src/main/java/com/github/sttk/sabi/internal/DataSrcManager.java b/src/main/java/com/github/sttk/sabi/internal/DataSrcManager.java index 80f5c84..be46767 100644 --- a/src/main/java/com/github/sttk/sabi/internal/DataSrcManager.java +++ b/src/main/java/com/github/sttk/sabi/internal/DataSrcManager.java @@ -63,7 +63,7 @@ List setup() { int ii = 0, nDone = 0; for (int i = 0, n = this.listUnready.size(); i < n; i++) { var cont = this.listUnready.get(i); - if (cont == null || cont.ds == null) { + if (cont.ds == null) { continue; } ag._name = cont.name; @@ -121,7 +121,7 @@ List setupWithOrder(List names) { for (int listIndex = 0, n = this.listUnready.size(); listIndex < n; listIndex++) { var cont = this.listUnready.get(listIndex); - if (cont != null && cont.ds != null) { + if (cont.ds != null) { Integer orderIndex = indexedMap.get(cont.name); if (orderIndex != null) { orderedIndexes.set(orderIndex, listIndex); diff --git a/src/test/java/com/github/sttk/sabi/internal/AsyncGroupImplTest.java b/src/test/java/com/github/sttk/sabi/internal/AsyncGroupImplTest.java index 2a7098e..26741e0 100644 --- a/src/test/java/com/github/sttk/sabi/internal/AsyncGroupImplTest.java +++ b/src/test/java/com/github/sttk/sabi/internal/AsyncGroupImplTest.java @@ -4,6 +4,7 @@ import static org.assertj.core.api.Assertions.fail; import com.github.sttk.errs.Err; +import com.github.sttk.sabi.AsyncGroup; import com.github.sttk.sabi.Runner; import org.junit.jupiter.api.Test; @@ -133,16 +134,85 @@ record Reason2() {} assertThat(errors.get(0).name).isEqualTo("foo2"); assertThat(errors.get(0).err.toString()) .isEqualTo( - "com.github.sttk.errs.Err { reason = com.github.sttk.sabi.internal.AsyncGroupImplTest$1Reason2 Reason2[], file = AsyncGroupImplTest.java, line = 114 }"); + "com.github.sttk.errs.Err { reason = com.github.sttk.sabi.internal.AsyncGroupImplTest$1Reason2 Reason2[], file = AsyncGroupImplTest.java, line = 115 }"); assertThat(errors.get(1).index).isEqualTo(123); assertThat(errors.get(1).name).isEqualTo("foo0"); assertThat(errors.get(1).err.toString()) .isEqualTo( - "com.github.sttk.errs.Err { reason = com.github.sttk.sabi.internal.AsyncGroupImplTest$1Reason0 Reason0[], file = AsyncGroupImplTest.java, line = 96 }"); + "com.github.sttk.errs.Err { reason = com.github.sttk.sabi.internal.AsyncGroupImplTest$1Reason0 Reason0[], file = AsyncGroupImplTest.java, line = 97 }"); assertThat(errors.get(2).index).isEqualTo(456); assertThat(errors.get(2).name).isEqualTo("foo1"); assertThat(errors.get(2).err.toString()) .isEqualTo( - "com.github.sttk.errs.Err { reason = com.github.sttk.sabi.internal.AsyncGroupImplTest$1Reason1 Reason1[], file = AsyncGroupImplTest.java, line = 105 }"); + "com.github.sttk.errs.Err { reason = com.github.sttk.sabi.internal.AsyncGroupImplTest$1Reason1 Reason1[], file = AsyncGroupImplTest.java, line = 106 }"); + } + + @Test + void runButRuntimeExceptionIsThrown() { + var ag = new AsyncGroupImpl(); + + boolean[] executed = {false}; + Runner fn = + () -> { + try { + Thread.sleep(50); + } catch (Exception e) { + fail(e); + } + executed[0] = true; + throw new RuntimeException("error"); + }; + + ag._index = 123; + ag._name = "foo"; + ag.add(fn); + assertThat(executed[0]).isFalse(); + + var errors = ag.join(); + assertThat(executed[0]).isTrue(); + assertThat(errors).hasSize(1); + + assertThat(errors.get(0).index).isEqualTo(123); + assertThat(errors.get(0).name).isEqualTo("foo"); + switch (errors.get(0).err.getReason()) { + case AsyncGroup.RuntimeExceptionOccured r -> {} + default -> fail(); + } + assertThat(errors.get(0).err.getCause().getMessage()).isEqualTo("error"); + assertThat(errors.get(0).err.getCause()).isInstanceOf(RuntimeException.class); + } + + @Test + void runButInterruptedExceptionIsThrown() { + var ag = new AsyncGroupImpl(); + + final var mainThread = Thread.currentThread(); + boolean[] executed = {false}; + Runner fn = + () -> { + try { + Thread.sleep(500); + } catch (Exception e) { + } + executed[0] = true; + mainThread.interrupt(); + }; + + ag._index = 123; + ag._name = "foo"; + ag.add(fn); + assertThat(executed[0]).isFalse(); + + var errors = ag.join(); + assertThat(executed[0]).isTrue(); + assertThat(errors).hasSize(1); + + assertThat(errors.get(0).index).isEqualTo(123); + assertThat(errors.get(0).name).isEqualTo("foo"); + switch (errors.get(0).err.getReason()) { + case AsyncGroup.RunnerInterrupted r -> {} + default -> fail(); + } + assertThat(errors.get(0).err.getCause()).isInstanceOf(InterruptedException.class); } } diff --git a/src/test/java/com/github/sttk/sabi/internal/DataConnManagerTest.java b/src/test/java/com/github/sttk/sabi/internal/DataConnManagerTest.java index f39566d..cf64c9f 100644 --- a/src/test/java/com/github/sttk/sabi/internal/DataConnManagerTest.java +++ b/src/test/java/com/github/sttk/sabi/internal/DataConnManagerTest.java @@ -25,6 +25,10 @@ static enum Fail { PostCommit, Rollback, PreCommitBecomeCommitted, + PreCommitByRuntimeException, + CommitByRuntimeException, + PostCommitByRuntimeException, + RollbackByRuntimeException, } static class SyncDataConn implements DataConn { @@ -46,6 +50,10 @@ public void commit(AsyncGroup ag) throws Err { this.logger.add(String.format("SyncDataConn#commit %d failed", this.id)); throw new Err("ZZZ"); } + if (this.fail == Fail.CommitByRuntimeException) { + this.logger.add(String.format("SyncDataConn#commit %d runtime error", this.id)); + throw new RuntimeException("R"); + } this.committed = true; this.logger.add(String.format("SyncDataConn#commit %d", this.id)); } @@ -56,6 +64,10 @@ public void preCommit(AsyncGroup ag) throws Err { this.logger.add(String.format("SyncDataConn#preCommit %d failed", this.id)); throw new Err("zzz"); } + if (this.fail == Fail.PreCommitByRuntimeException) { + this.logger.add(String.format("SyncDataConn#preCommit %d runtime error", this.id)); + throw new RuntimeException("RR"); + } this.logger.add(String.format("SyncDataConn#preCommit %d", this.id)); if (this.fail == Fail.PreCommitBecomeCommitted) { this.committed = true; @@ -68,6 +80,10 @@ public void postCommit(AsyncGroup ag) throws Err { this.logger.add(String.format("SyncDataConn#postCommit %d failed", this.id)); throw new Err("!!!"); } + if (this.fail == Fail.PostCommitByRuntimeException) { + this.logger.add(String.format("SyncDataConn#postCommit %d runtime error", this.id)); + throw new RuntimeException("RRR"); + } this.logger.add(String.format("SyncDataConn#postCommit %d", this.id)); } @@ -82,6 +98,10 @@ public void rollback(AsyncGroup ag) throws Err { this.logger.add(String.format("SyncDataConn#rollback %d failed", this.id)); throw new Err("???"); } + if (this.fail == Fail.RollbackByRuntimeException) { + this.logger.add(String.format("SyncDataConn#rollback %d runtime error", this.id)); + throw new RuntimeException("RRRR"); + } this.logger.add(String.format("SyncDataConn#rollback %d", this.id)); } @@ -122,6 +142,10 @@ public void commit(AsyncGroup ag) throws Err { this.logger.add(String.format("AsyncDataConn#commit %d failed", this.id)); throw new Err("YYY"); } + if (this.fail == Fail.CommitByRuntimeException) { + this.logger.add(String.format("AsyncDataConn#commit %d runtime error", this.id)); + throw new RuntimeException("r"); + } this.committed = true; this.logger.add(String.format("AsyncDataConn#commit %d", this.id)); }); @@ -139,6 +163,10 @@ public void preCommit(AsyncGroup ag) throws Err { this.logger.add(String.format("AsyncDataConn#preCommit %d failed", this.id)); throw new Err("yyy"); } + if (this.fail == Fail.PreCommitByRuntimeException) { + this.logger.add(String.format("AsyncDataConn#preCommit %d runtime error", this.id)); + throw new RuntimeException("rr"); + } this.logger.add(String.format("AsyncDataConn#preCommit %d", this.id)); if (this.fail == Fail.PreCommitBecomeCommitted) { this.committed = true; @@ -158,6 +186,10 @@ public void postCommit(AsyncGroup ag) throws Err { this.logger.add(String.format("AsyncDataConn#postCommit %d failed", this.id)); throw new Err("!!!"); } + if (this.fail == Fail.PostCommitByRuntimeException) { + this.logger.add(String.format("AsyncDataConn#postCommit %d runtime error", this.id)); + throw new RuntimeException("rrr"); + } this.logger.add(String.format("AsyncDataConn#postCommit %d", this.id)); }); } @@ -179,6 +211,10 @@ public void rollback(AsyncGroup ag) throws Err { this.logger.add(String.format("AsyncDataConn#rollback %d failed", this.id)); throw new Err("???"); } + if (this.fail == Fail.RollbackByRuntimeException) { + this.logger.add(String.format("AsyncDataConn#rollback %d runtime error", this.id)); + throw new RuntimeException("rrrr"); + } this.logger.add(String.format("AsyncDataConn#rollback %d", this.id)); }); } @@ -515,11 +551,11 @@ void testCommitAndRollbackButFailFirstSyncPreCommit() { assertThat(iter.next()).isEqualTo("SyncDataConn#onTxnFailure 1"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:LogicFailure Err:com.github.sttk.errs.Err { reason = java.lang.String zzz, file = DataConnManagerTest.java, line = 57 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:LogicFailure Err:com.github.sttk.errs.Err { reason = java.lang.String zzz, file = DataConnManagerTest.java, line = 65 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#onTxnFailure 2"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:LogicFailure Err:com.github.sttk.errs.Err { reason = java.lang.String zzz, file = DataConnManagerTest.java, line = 57 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:LogicFailure Err:com.github.sttk.errs.Err { reason = java.lang.String zzz, file = DataConnManagerTest.java, line = 65 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#close 2"); assertThat(iter.next()).isEqualTo("SyncDataConn#close 1"); assertThat(iter.hasNext()).isFalse(); @@ -574,16 +610,72 @@ void testCommitAndRollbackButFailFirstAsyncPreCommit() { assertThat(iter.next()).isEqualTo("SyncDataConn#onTxnFailure 2"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:LogicFailure Err:com.github.sttk.errs.Err { reason = java.lang.String yyy, file = DataConnManagerTest.java, line = 140 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:LogicFailure Err:com.github.sttk.errs.Err { reason = java.lang.String zzz, file = DataConnManagerTest.java, line = 57 }} rollback:{State:NoneByRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:LogicFailure Err:com.github.sttk.errs.Err { reason = java.lang.String yyy, file = DataConnManagerTest.java, line = 164 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:LogicFailure Err:com.github.sttk.errs.Err { reason = java.lang.String zzz, file = DataConnManagerTest.java, line = 65 }} rollback:{State:NoneByRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#onTxnFailure 1"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:LogicFailure Err:com.github.sttk.errs.Err { reason = java.lang.String yyy, file = DataConnManagerTest.java, line = 140 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:LogicFailure Err:com.github.sttk.errs.Err { reason = java.lang.String zzz, file = DataConnManagerTest.java, line = 57 }} rollback:{State:NoneByRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:LogicFailure Err:com.github.sttk.errs.Err { reason = java.lang.String yyy, file = DataConnManagerTest.java, line = 164 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:LogicFailure Err:com.github.sttk.errs.Err { reason = java.lang.String zzz, file = DataConnManagerTest.java, line = 65 }} rollback:{State:NoneByRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("SyncDataConn#close 2"); assertThat(iter.next()).isEqualTo("AsyncDataConn#close 1"); assertThat(iter.hasNext()).isFalse(); } + @Test + void testCommitAndRollbackButFirstSyncPreCommitThrowsRuntimeException() { + var logger = new ArrayList(); + + var manager = new DataConnManager(); + try { + var conn1 = new SyncDataConn(1, logger, Fail.PreCommitByRuntimeException); + manager.add(new DataConnContainer("foo", conn1)); + + var conn2 = new AsyncDataConn(2, logger, Fail.Not); + manager.add(new DataConnContainer("bar", conn2)); + + var reportBuilders = new ArrayList(); + manager.prepareTxnFailureReportBuilders(reportBuilders); + + try { + manager.commit(reportBuilders); + } catch (Err err) { + switch (err.getReason()) { + case FailToPreCommitDataConn rsn -> { + assertThat(rsn.errors()).hasSize(1); + var ee = rsn.errors().get(0); + assertThat(ee.index).isEqualTo(0); + assertThat(ee.name).isEqualTo("foo"); + assertThat(ee.err.getReason()).isInstanceOf(AsyncGroup.RuntimeExceptionOccured.class); + assertThat(ee.err.getCause()).isInstanceOf(RuntimeException.class); + assertThat(ee.err.getCause().getMessage()).isEqualTo("RR"); + } + default -> fail(err); + } + manager.rollback(reportBuilders); + } catch (Exception e) { + fail(e); + } + } finally { + manager.close(); + } + + assertThat(logger).hasSize(9); + var iter = logger.iterator(); + assertThat(iter.next()).isEqualTo("SyncDataConn#preCommit 1 runtime error"); + assertThat(iter.next()).isEqualTo("SyncDataConn#rollback 1"); + assertThat(iter.next()).isEqualTo("AsyncDataConn#rollback 2"); + assertThat(iter.next()).isEqualTo("SyncDataConn#onTxnFailure 1"); + assertThat(iter.next()) + .isEqualTo( + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:LogicFailure Err:com.github.sttk.errs.Err { reason = com.github.sttk.sabi.AsyncGroup$RuntimeExceptionOccured RuntimeExceptionOccured[], file = AsyncGroupImpl.java, line = 58, cause = java.lang.RuntimeException: RR }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}]"); + assertThat(iter.next()).isEqualTo("AsyncDataConn#onTxnFailure 2"); + assertThat(iter.next()) + .isEqualTo( + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:LogicFailure Err:com.github.sttk.errs.Err { reason = com.github.sttk.sabi.AsyncGroup$RuntimeExceptionOccured RuntimeExceptionOccured[], file = AsyncGroupImpl.java, line = 58, cause = java.lang.RuntimeException: RR }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}]"); + assertThat(iter.next()).isEqualTo("AsyncDataConn#close 2"); + assertThat(iter.next()).isEqualTo("SyncDataConn#close 1"); + assertThat(iter.hasNext()).isFalse(); + } + @Test void testCommitAndRollbackButFailSecondPreCommit() { var logger = new ArrayList(); @@ -629,11 +721,11 @@ void testCommitAndRollbackButFailSecondPreCommit() { assertThat(iter.next()).isEqualTo("SyncDataConn#onTxnFailure 1"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:LogicFailure Err:com.github.sttk.errs.Err { reason = java.lang.String yyy, file = DataConnManagerTest.java, line = 140 }} rollback:{State:NoneByRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:LogicFailure Err:com.github.sttk.errs.Err { reason = java.lang.String yyy, file = DataConnManagerTest.java, line = 164 }} rollback:{State:NoneByRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#onTxnFailure 2"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:LogicFailure Err:com.github.sttk.errs.Err { reason = java.lang.String yyy, file = DataConnManagerTest.java, line = 140 }} rollback:{State:NoneByRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:LogicFailure Err:com.github.sttk.errs.Err { reason = java.lang.String yyy, file = DataConnManagerTest.java, line = 164 }} rollback:{State:NoneByRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#close 2"); assertThat(iter.next()).isEqualTo("SyncDataConn#close 1"); assertThat(iter.hasNext()).isFalse(); @@ -685,11 +777,11 @@ void testCommitAndRollbackButFailFirstSyncCommit() { assertThat(iter.next()).isEqualTo("SyncDataConn#onTxnFailure 1"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ZZZ, file = DataConnManagerTest.java, line = 47 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ZZZ, file = DataConnManagerTest.java, line = 51 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#onTxnFailure 2"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ZZZ, file = DataConnManagerTest.java, line = 47 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ZZZ, file = DataConnManagerTest.java, line = 51 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#close 2"); assertThat(iter.next()).isEqualTo("SyncDataConn#close 1"); assertThat(iter.hasNext()).isFalse(); @@ -746,11 +838,11 @@ void testCommitAndRollbackButFailFirstAsyncCommit() { assertThat(iter.next()).isEqualTo("SyncDataConn#onTxnFailure 2"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String YYY, file = DataConnManagerTest.java, line = 123 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ZZZ, file = DataConnManagerTest.java, line = 47 }} rollback:{State:NoneByRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String YYY, file = DataConnManagerTest.java, line = 143 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ZZZ, file = DataConnManagerTest.java, line = 51 }} rollback:{State:NoneByRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#onTxnFailure 1"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String YYY, file = DataConnManagerTest.java, line = 123 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ZZZ, file = DataConnManagerTest.java, line = 47 }} rollback:{State:NoneByRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String YYY, file = DataConnManagerTest.java, line = 143 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ZZZ, file = DataConnManagerTest.java, line = 51 }} rollback:{State:NoneByRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("SyncDataConn#close 2"); assertThat(iter.next()).isEqualTo("AsyncDataConn#close 1"); assertThat(iter.hasNext()).isFalse(); @@ -802,11 +894,69 @@ void testCommitAndRollbackButFailSecondCommit() { assertThat(iter.next()).isEqualTo("SyncDataConn#onTxnFailure 1"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByCommitted Err:null} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String YYY, file = DataConnManagerTest.java, line = 123 }} rollback:{State:NoneByRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByCommitted Err:null} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String YYY, file = DataConnManagerTest.java, line = 143 }} rollback:{State:NoneByRolledBack Err:null}}]"); + assertThat(iter.next()).isEqualTo("AsyncDataConn#onTxnFailure 2"); + assertThat(iter.next()) + .isEqualTo( + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByCommitted Err:null} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String YYY, file = DataConnManagerTest.java, line = 143 }} rollback:{State:NoneByRolledBack Err:null}}]"); + assertThat(iter.next()).isEqualTo("AsyncDataConn#close 2"); + assertThat(iter.next()).isEqualTo("SyncDataConn#close 1"); + assertThat(iter.hasNext()).isFalse(); + } + + @Test + void testCommitAndRollbackButFirstCommitThrowsRuntimeException() { + var logger = new ArrayList(); + + var manager = new DataConnManager(); + try { + var conn1 = new SyncDataConn(1, logger, Fail.CommitByRuntimeException); + manager.add(new DataConnContainer("foo", conn1)); + + var conn2 = new AsyncDataConn(2, logger, Fail.Not); + manager.add(new DataConnContainer("bar", conn2)); + + var reportBuilders = new ArrayList(); + manager.prepareTxnFailureReportBuilders(reportBuilders); + + try { + manager.commit(reportBuilders); + } catch (Err err) { + switch (err.getReason()) { + case FailToCommitDataConn rsn -> { + assertThat(rsn.errors()).hasSize(1); + var ee = rsn.errors().get(0); + assertThat(ee.index).isEqualTo(0); + assertThat(ee.name).isEqualTo("foo"); + assertThat(ee.err.getReason()).isInstanceOf(AsyncGroup.RuntimeExceptionOccured.class); + assertThat(ee.err.getCause()).isInstanceOf(RuntimeException.class); + assertThat(ee.err.getCause().getMessage()).isEqualTo("R"); + } + default -> fail(err); + } + manager.rollback(reportBuilders); + } catch (Exception e) { + fail(e); + } + } finally { + manager.close(); + } + + assertThat(logger).hasSize(11); + var iter = logger.iterator(); + assertThat(iter.next()).isEqualTo("SyncDataConn#preCommit 1"); + assertThat(iter.next()).isEqualTo("AsyncDataConn#preCommit 2"); + assertThat(iter.next()).isEqualTo("SyncDataConn#commit 1 runtime error"); + assertThat(iter.next()).isEqualTo("SyncDataConn#rollback 1"); + assertThat(iter.next()).isEqualTo("AsyncDataConn#rollback 2"); + assertThat(iter.next()).isEqualTo("SyncDataConn#onTxnFailure 1"); + assertThat(iter.next()) + .isEqualTo( + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = com.github.sttk.sabi.AsyncGroup$RuntimeExceptionOccured RuntimeExceptionOccured[], file = AsyncGroupImpl.java, line = 58, cause = java.lang.RuntimeException: R }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#onTxnFailure 2"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByCommitted Err:null} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String YYY, file = DataConnManagerTest.java, line = 123 }} rollback:{State:NoneByRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = com.github.sttk.sabi.AsyncGroup$RuntimeExceptionOccured RuntimeExceptionOccured[], file = AsyncGroupImpl.java, line = 58, cause = java.lang.RuntimeException: R }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#close 2"); assertThat(iter.next()).isEqualTo("SyncDataConn#close 1"); assertThat(iter.hasNext()).isFalse(); @@ -863,11 +1013,11 @@ void testCommitAndRollbackButFailFirstSyncPostCommit() { assertThat(iter.next()).isEqualTo("SyncDataConn#onTxnFailure 1"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 69 }} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 159 }} rollback:{State:NoneByNotRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 81 }} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 187 }} rollback:{State:NoneByNotRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#onTxnFailure 2"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 69 }} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 159 }} rollback:{State:NoneByNotRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 81 }} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 187 }} rollback:{State:NoneByNotRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#close 2"); assertThat(iter.next()).isEqualTo("SyncDataConn#close 1"); assertThat(iter.hasNext()).isFalse(); @@ -924,11 +1074,11 @@ void testCommitAndRollbackButFailFirstAsyncPostCommit() { assertThat(iter.next()).isEqualTo("SyncDataConn#onTxnFailure 1"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 159 }} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 69 }} rollback:{State:NoneByNotRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 187 }} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 81 }} rollback:{State:NoneByNotRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#onTxnFailure 2"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 159 }} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 69 }} rollback:{State:NoneByNotRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 187 }} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 81 }} rollback:{State:NoneByNotRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("SyncDataConn#close 1"); assertThat(iter.next()).isEqualTo("AsyncDataConn#close 2"); assertThat(iter.hasNext()).isFalse(); @@ -981,11 +1131,70 @@ void testCommitAndRollbackButFailSecondPostCommit() { assertThat(iter.next()).isEqualTo("SyncDataConn#onTxnFailure 1"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByCommitted Err:null} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 159 }} rollback:{State:NoneByNotRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByCommitted Err:null} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 187 }} rollback:{State:NoneByNotRolledBack Err:null}}]"); + assertThat(iter.next()).isEqualTo("AsyncDataConn#onTxnFailure 2"); + assertThat(iter.next()) + .isEqualTo( + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByCommitted Err:null} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 187 }} rollback:{State:NoneByNotRolledBack Err:null}}]"); + assertThat(iter.next()).isEqualTo("AsyncDataConn#close 2"); + assertThat(iter.next()).isEqualTo("SyncDataConn#close 1"); + assertThat(iter.hasNext()).isFalse(); + } + + @Test + void testCommitAndRollbackButSecondPostCommitThrowsRuntimException() { + var logger = new ArrayList(); + + var manager = new DataConnManager(); + try { + var conn1 = new SyncDataConn(1, logger, Fail.PostCommitByRuntimeException); + manager.add(new DataConnContainer("foo", conn1)); + + var conn2 = new AsyncDataConn(2, logger, Fail.Not); + manager.add(new DataConnContainer("bar", conn2)); + + var reportBuilders = new ArrayList(); + manager.prepareTxnFailureReportBuilders(reportBuilders); + + try { + manager.commit(reportBuilders); + } catch (Err err) { + switch (err.getReason()) { + case FailToPostCommitDataConn rsn -> { + assertThat(rsn.errors()).hasSize(1); + var ee = rsn.errors().get(0); + assertThat(ee.index).isEqualTo(0); + assertThat(ee.name).isEqualTo("foo"); + assertThat(ee.err.getReason()).isInstanceOf(AsyncGroup.RuntimeExceptionOccured.class); + assertThat(ee.err.getCause()).isInstanceOf(RuntimeException.class); + assertThat(ee.err.getCause().getMessage()).isEqualTo("RRR"); + } + default -> fail(err); + } + manager.rollback(reportBuilders); + } catch (Exception e) { + fail(e); + } + } finally { + manager.close(); + } + + assertThat(logger).hasSize(12); + var iter = logger.iterator(); + assertThat(iter.next()).isEqualTo("SyncDataConn#preCommit 1"); + assertThat(iter.next()).isEqualTo("AsyncDataConn#preCommit 2"); + assertThat(iter.next()).isEqualTo("SyncDataConn#commit 1"); + assertThat(iter.next()).isEqualTo("AsyncDataConn#commit 2"); + assertThat(iter.next()).isEqualTo("SyncDataConn#postCommit 1 runtime error"); + assertThat(iter.next()).isEqualTo("AsyncDataConn#postCommit 2"); + assertThat(iter.next()).isEqualTo("SyncDataConn#onTxnFailure 1"); + assertThat(iter.next()) + .isEqualTo( + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = com.github.sttk.sabi.AsyncGroup$RuntimeExceptionOccured RuntimeExceptionOccured[], file = AsyncGroupImpl.java, line = 58, cause = java.lang.RuntimeException: RRR }} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByCommitted Err:null} rollback:{State:NoneByNotRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#onTxnFailure 2"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByCommitted Err:null} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String !!!, file = DataConnManagerTest.java, line = 159 }} rollback:{State:NoneByNotRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:PostCommitFailure Err:com.github.sttk.errs.Err { reason = com.github.sttk.sabi.AsyncGroup$RuntimeExceptionOccured RuntimeExceptionOccured[], file = AsyncGroupImpl.java, line = 58, cause = java.lang.RuntimeException: RRR }} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByCommitted Err:null} rollback:{State:NoneByNotRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#close 2"); assertThat(iter.next()).isEqualTo("SyncDataConn#close 1"); assertThat(iter.hasNext()).isFalse(); @@ -1092,11 +1301,11 @@ void testOnlyRollbackAndSecondRollbackFailed() { assertThat(iter.next()).isEqualTo("SyncDataConn#onTxnFailure 2"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:RollbackFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ???, file = DataConnManagerTest.java, line = 83 }}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:RollbackFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ???, file = DataConnManagerTest.java, line = 99 }}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#onTxnFailure 1"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:RollbackFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ???, file = DataConnManagerTest.java, line = 83 }}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:RollbackFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ???, file = DataConnManagerTest.java, line = 99 }}}]"); assertThat(iter.next()).isEqualTo("SyncDataConn#close 2"); assertThat(iter.next()).isEqualTo("AsyncDataConn#close 1"); assertThat(iter.hasNext()).isFalse(); @@ -1129,11 +1338,48 @@ void testOnlyRollbackAndFirstRollbackFailed() { assertThat(iter.next()).isEqualTo("SyncDataConn#onTxnFailure 1"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:RollbackFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ???, file = DataConnManagerTest.java, line = 83 }}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:RollbackFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ???, file = DataConnManagerTest.java, line = 99 }}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#onTxnFailure 2"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:RollbackFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ???, file = DataConnManagerTest.java, line = 83 }}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:RollbackFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ???, file = DataConnManagerTest.java, line = 99 }}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}]"); + assertThat(iter.next()).isEqualTo("AsyncDataConn#close 2"); + assertThat(iter.next()).isEqualTo("SyncDataConn#close 1"); + assertThat(iter.hasNext()).isFalse(); + } + + @Test + void testOnlyRollbackAndFirstRollbackThrowsRuntimeException() { + var logger = new ArrayList(); + + var manager = new DataConnManager(); + try { + var conn1 = new SyncDataConn(1, logger, Fail.RollbackByRuntimeException); + manager.add(new DataConnContainer("foo", conn1)); + + var conn2 = new AsyncDataConn(2, logger, Fail.Not); + manager.add(new DataConnContainer("bar", conn2)); + + var reportBuilders = new ArrayList(); + manager.prepareTxnFailureReportBuilders(reportBuilders); + + manager.rollback(reportBuilders); + } finally { + manager.close(); + } + + assertThat(logger).hasSize(8); + var iter = logger.iterator(); + assertThat(iter.next()).isEqualTo("SyncDataConn#rollback 1 runtime error"); + assertThat(iter.next()).isEqualTo("AsyncDataConn#rollback 2"); + assertThat(iter.next()).isEqualTo("SyncDataConn#onTxnFailure 1"); + assertThat(iter.next()) + .isEqualTo( + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:RollbackFailure Err:com.github.sttk.errs.Err { reason = com.github.sttk.sabi.AsyncGroup$RuntimeExceptionOccured RuntimeExceptionOccured[], file = AsyncGroupImpl.java, line = 58, cause = java.lang.RuntimeException: RRRR }}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}]"); + assertThat(iter.next()).isEqualTo("AsyncDataConn#onTxnFailure 2"); + assertThat(iter.next()) + .isEqualTo( + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:RollbackFailure Err:com.github.sttk.errs.Err { reason = com.github.sttk.sabi.AsyncGroup$RuntimeExceptionOccured RuntimeExceptionOccured[], file = AsyncGroupImpl.java, line = 58, cause = java.lang.RuntimeException: RRRR }}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:NoneByRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#close 2"); assertThat(iter.next()).isEqualTo("SyncDataConn#close 1"); assertThat(iter.hasNext()).isFalse(); @@ -1185,11 +1431,11 @@ void testCommitAndRollbackAndFirstRollbackFailedThenSecondRollbackFailed() { assertThat(iter.next()).isEqualTo("SyncDataConn#onTxnFailure 1"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ZZZ, file = DataConnManagerTest.java, line = 47 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:RollbackFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ???, file = DataConnManagerTest.java, line = 180 }}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ZZZ, file = DataConnManagerTest.java, line = 51 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:RollbackFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ???, file = DataConnManagerTest.java, line = 212 }}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#onTxnFailure 2"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ZZZ, file = DataConnManagerTest.java, line = 47 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:RollbackFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ???, file = DataConnManagerTest.java, line = 180 }}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ZZZ, file = DataConnManagerTest.java, line = 51 }} rollback:{State:NoneByRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:NoneByUncommitted Err:null} rollback:{State:RollbackFailure Err:com.github.sttk.errs.Err { reason = java.lang.String ???, file = DataConnManagerTest.java, line = 212 }}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#close 2"); assertThat(iter.next()).isEqualTo("SyncDataConn#close 1"); assertThat(iter.hasNext()).isFalse(); @@ -1241,11 +1487,11 @@ void testCommitAndRollbackAndSecondCommitFailedThenFirstRollbackFailed() { assertThat(iter.next()).isEqualTo("SyncDataConn#onTxnFailure 1"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByCommitted Err:null} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String YYY, file = DataConnManagerTest.java, line = 123 }} rollback:{State:NoneByRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByCommitted Err:null} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String YYY, file = DataConnManagerTest.java, line = 143 }} rollback:{State:NoneByRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#onTxnFailure 2"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByCommitted Err:null} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String YYY, file = DataConnManagerTest.java, line = 123 }} rollback:{State:NoneByRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByCommitted Err:null} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String YYY, file = DataConnManagerTest.java, line = 143 }} rollback:{State:NoneByRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#close 2"); assertThat(iter.next()).isEqualTo("SyncDataConn#close 1"); assertThat(iter.hasNext()).isFalse(); @@ -1340,13 +1586,40 @@ void testCommitAndRollbackAndPreCommitBecomeCommittedButFailed() { assertThat(iter.next()).isEqualTo("SyncDataConn#onTxnFailure 1"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByCommitted Err:null} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String YYY, file = DataConnManagerTest.java, line = 123 }} rollback:{State:NoneByRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByCommitted Err:null} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String YYY, file = DataConnManagerTest.java, line = 143 }} rollback:{State:NoneByRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#onTxnFailure 2"); assertThat(iter.next()) .isEqualTo( - "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByCommitted Err:null} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String YYY, file = DataConnManagerTest.java, line = 123 }} rollback:{State:NoneByRolledBack Err:null}}]"); + "TxnFailureReports=[{dataConnName:foo dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$SyncDataConn cause:{State:NoneByCommitted Err:null} rollback:{State:NoneByNotRolledBack Err:null}}, {dataConnName:bar dataConnType:com.github.sttk.sabi.internal.DataConnManagerTest$AsyncDataConn cause:{State:CommitFailure Err:com.github.sttk.errs.Err { reason = java.lang.String YYY, file = DataConnManagerTest.java, line = 143 }} rollback:{State:NoneByRolledBack Err:null}}]"); assertThat(iter.next()).isEqualTo("AsyncDataConn#close 2"); assertThat(iter.next()).isEqualTo("SyncDataConn#close 1"); assertThat(iter.hasNext()).isFalse(); } + + @Test + void testDefaultMethodOfDataConn() throws Err { + var conn = + new DataConn() { + @Override + public void commit(AsyncGroup ag) throws Err {} + + @Override + public void rollback(AsyncGroup ag) throws Err {} + + @Override + public void close() {} + + @Override + public boolean isCommitted() { + return true; + } + }; + + conn.preCommit(null); + conn.commit(null); + conn.postCommit(null); + conn.rollback(null); + conn.onTxnFailure(null, null); + conn.close(); + } } diff --git a/src/test/java/com/github/sttk/sabi/internal/DataHubInnerTest.java b/src/test/java/com/github/sttk/sabi/internal/DataHubInnerTest.java index 6b33b6e..bae4554 100644 --- a/src/test/java/com/github/sttk/sabi/internal/DataHubInnerTest.java +++ b/src/test/java/com/github/sttk/sabi/internal/DataHubInnerTest.java @@ -610,6 +610,16 @@ void testBeginButFailed() { assertThat(iter.hasNext()).isFalse(); } + @Test + void testUseAndDisuses() { + var logger = new ArrayList(); + + try (var hub = new DataHub()) { + hub.uses("foo", new MyDataSrc(1, Failure.None, logger)); + hub.disuses("foo"); + } + } + @Nested class RunTest { @Test @@ -701,6 +711,37 @@ void testRunButFailToCastToSpecifiedDataHub() { assertThat(iter.hasNext()).isFalse(); } + @Test + void testRunButDataHubThrowsRuntimeException() { + var logger = new ArrayList(); + + try (var hub = new DataHub()) { + hub.uses("foo", new MyDataSrc(1, Failure.None, logger)); + hub.uses("bar", new MyDataSrc(2, Failure.None, logger)); + + hub.run( + data -> { + throw new RuntimeException(); + }); + } catch (Err err) { + switch (err.getReason()) { + case DataHub.RuntimeExceptionOccurred r -> {} + default -> fail(err); + } + assertThat(err.getCause()).isInstanceOf(RuntimeException.class); + } catch (Exception e) { + fail(e); + } + + assertThat(logger).hasSize(4); + var iter = logger.iterator(); + assertThat(iter.next()).isEqualTo("MyDataSrc#setup 1"); + assertThat(iter.next()).isEqualTo("MyDataSrc#setup 2"); + assertThat(iter.next()).isEqualTo("MyDataSrc#close 2"); + assertThat(iter.next()).isEqualTo("MyDataSrc#close 1"); + assertThat(iter.hasNext()).isFalse(); + } + @Test void testRunButFailToSetup() { var logger = new ArrayList(); @@ -1140,6 +1181,37 @@ void testTxnButFailToCastToSpecifiedDataHub() { assertThat(iter.hasNext()).isFalse(); } + @Test + void testTxnButDataHubThrowsRuntimeException() { + var logger = new ArrayList(); + + try (var hub = new DataHub()) { + hub.uses("foo", new MyDataSrc(1, Failure.None, logger)); + hub.uses("bar", new MyDataSrc(2, Failure.None, logger)); + + hub.txn( + data -> { + throw new RuntimeException(); + }); + } catch (Err err) { + switch (err.getReason()) { + case DataHub.RuntimeExceptionOccurred r -> {} + default -> fail(err); + } + assertThat(err.getCause()).isInstanceOf(RuntimeException.class); + } catch (Exception e) { + fail(e); + } + + assertThat(logger).hasSize(4); + var iter = logger.iterator(); + assertThat(iter.next()).isEqualTo("MyDataSrc#setup 1"); + assertThat(iter.next()).isEqualTo("MyDataSrc#setup 2"); + assertThat(iter.next()).isEqualTo("MyDataSrc#close 2"); + assertThat(iter.next()).isEqualTo("MyDataSrc#close 1"); + assertThat(iter.hasNext()).isFalse(); + } + @Test void testTxnButFailToSetup() { var logger = new ArrayList(); @@ -1319,38 +1391,38 @@ void testGetDataConnAndFailedToCastDataConn() { @SuppressWarnings("unused") var dc1 = data.getDataConn("foo", MyDataConn.class); + try { + data.getDataConn("bar", BadDataConn.class); + } catch (Err err) { + switch (err.getReason()) { + case FailToCastDataConn r -> { + assertThat(r.name()).isEqualTo("bar"); + assertThat(r.fromDataConnType()).isEqualTo(MyDataConn.class.getName()); + assertThat(r.toDataConnType()).isEqualTo(BadDataConn.class.getName()); + } + default -> fail(err); + } + } + @SuppressWarnings("unused") - var dc2 = data.getDataConn("bar", BadDataConn.class); + var dc2 = data.getDataConn("bar", MyDataConn.class); + + try { + data.getDataConn("bar", BadDataConn.class); + } catch (Err err) { + switch (err.getReason()) { + case FailToCastDataConn r -> { + assertThat(r.name()).isEqualTo("bar"); + assertThat(r.fromDataConnType()).isEqualTo(MyDataConn.class.getName()); + assertThat(r.toDataConnType()).isEqualTo(BadDataConn.class.getName()); + } + default -> fail(err); + } + } }); - } catch (Err err) { - switch (err.getReason()) { - case FailToCastDataConn r -> { - assertThat(r.name()).isEqualTo("bar"); - assertThat(r.fromDataConnType()).isEqualTo(MyDataConn.class.getName()); - assertThat(r.toDataConnType()).isEqualTo(BadDataConn.class.getName()); - } - default -> fail(err); - } } catch (Exception e) { fail(e); } - - assertThat(logger).hasSize(13); - var iter = logger.iterator(); - assertThat(iter.next()).isEqualTo("MyDataSrc#setup 1"); - assertThat(iter.next()).isEqualTo("MyDataSrc#setup 2"); - assertThat(iter.next()).isEqualTo("execute logic"); - assertThat(iter.next()).isEqualTo("MyDataSrc#createDataConn 1"); - assertThat(iter.next()).isEqualTo("MyDataSrc#createDataConn 2"); - assertThat(iter.next()).isEqualTo("MyDataConn#rollback 1"); - assertThat(iter.next()).isEqualTo("MyDataConn#rollback 2"); - assertThat(iter.next()).isEqualTo("MyDataConn#onTxnFailure 1"); - assertThat(iter.next()).isEqualTo("MyDataConn#onTxnFailure 2"); - assertThat(iter.next()).isEqualTo("MyDataConn#close 2"); - assertThat(iter.next()).isEqualTo("MyDataConn#close 1"); - assertThat(iter.next()).isEqualTo("MyDataSrc#close 2"); - assertThat(iter.next()).isEqualTo("MyDataSrc#close 1"); - assertThat(iter.hasNext()).isFalse(); } } diff --git a/src/test/java/com/github/sttk/sabi/internal/DataSrcManagerTest.java b/src/test/java/com/github/sttk/sabi/internal/DataSrcManagerTest.java index 7182178..9face26 100644 --- a/src/test/java/com/github/sttk/sabi/internal/DataSrcManagerTest.java +++ b/src/test/java/com/github/sttk/sabi/internal/DataSrcManagerTest.java @@ -20,6 +20,7 @@ static enum Fail { Not, Setup, CreateDataConn, + SetupByRuntimeException, } static class SyncDataSrc implements DataSrc { @@ -40,6 +41,10 @@ public void setup(AsyncGroup ag) throws Err { this.logger.add(String.format("SyncDataSrc#setup %d failed", this.id)); throw new Err("XXX"); } + if (this.fail == Fail.SetupByRuntimeException) { + this.logger.add(String.format("SyncDataSrc#setup %d runtime error", this.id)); + throw new RuntimeException(); + } this.logger.add(String.format("SyncDataSrc#setup %d", this.id)); } @@ -79,6 +84,10 @@ public void setup(AsyncGroup ag) throws Err { this.logger.add(String.format("AsyncDataSrc#setup %d failed", this.id)); throw new Err("XXX"); } + if (this.fail == Fail.SetupByRuntimeException) { + this.logger.add(String.format("AsyncDataSrc#setup %d runtime error", this.id)); + throw new RuntimeException(); + } this.logger.add(String.format("AsyncDataSrc#setup %d", this.id)); }); } @@ -331,7 +340,7 @@ void setupButError() { assertThat(errors.get(0).name).isEqualTo("bar"); assertThat(errors.get(0).err.toString()) .isEqualTo( - "com.github.sttk.errs.Err { reason = java.lang.String XXX, file = DataSrcManagerTest.java, line = 41 }"); + "com.github.sttk.errs.Err { reason = java.lang.String XXX, file = DataSrcManagerTest.java, line = 42 }"); } finally { manager.close(); } @@ -348,7 +357,65 @@ void setupButError() { } @Test - void setupWithOrderNoDtaSrc() { + void setupButRuntimeException() { + var logger = new ArrayList(); + + var manager = new DataSrcManager(true); + try { + var ds1 = new SyncDataSrc(1, logger, Fail.SetupByRuntimeException); + manager.add("foo", ds1); + + var ds2 = new SyncDataSrc(2, logger, Fail.Not); + manager.add("bar", ds2); + + assertThat(manager.local).isTrue(); + assertThat(manager.listUnready).hasSize(2); + assertThat(manager.listReady).hasSize(0); + + var errors = manager.setup(); + + assertThat(manager.local).isTrue(); + assertThat(manager.listUnready).hasSize(2); + assertThat(manager.listReady).hasSize(0); + + assertThat(errors).hasSize(1); + assertThat(errors.get(0).index).isEqualTo(0); + assertThat(errors.get(0).name).isEqualTo("foo"); + assertThat(errors.get(0).err.toString()) + .isEqualTo( + "com.github.sttk.errs.Err { reason = com.github.sttk.sabi.AsyncGroup$RuntimeExceptionOccured RuntimeExceptionOccured[], file = AsyncGroupImpl.java, line = 58, cause = java.lang.RuntimeException }"); + } finally { + manager.close(); + } + } + + @Test + void setupButDsIsNull() { + var logger = new ArrayList(); + + var manager = new DataSrcManager(true); + try { + manager.add("foo", null); + + assertThat(manager.local).isTrue(); + assertThat(manager.listUnready).hasSize(1); + assertThat(manager.listReady).hasSize(0); + + var errors = manager.setup(); + assertThat(errors).hasSize(0); + + assertThat(manager.local).isTrue(); + assertThat(manager.listUnready).hasSize(0); + assertThat(manager.listReady).hasSize(0); + } finally { + manager.close(); + } + + assertThat(logger).hasSize(0); + } + + @Test + void setupWithOrderNoDataSrc() { var logger = new ArrayList(); var manager = new DataSrcManager(true); @@ -448,7 +515,7 @@ void setupWithOrdrAndFail() { assertThat(errors.get(0).name).isEqualTo("foo"); assertThat(errors.get(0).err.toString()) .isEqualTo( - "com.github.sttk.errs.Err { reason = java.lang.String XXX, file = DataSrcManagerTest.java, line = 41 }"); + "com.github.sttk.errs.Err { reason = java.lang.String XXX, file = DataSrcManagerTest.java, line = 42 }"); } finally { manager.close(); } @@ -632,6 +699,62 @@ void setupWithOrderButOneOfNamesIsNotUsed_2() { } } + @Test + void setupWithOrderButRuntimeException() { + var logger = new ArrayList(); + + var manager = new DataSrcManager(true); + try { + var ds1 = new SyncDataSrc(1, logger, Fail.SetupByRuntimeException); + manager.add("foo", ds1); + + var ds2 = new SyncDataSrc(2, logger, Fail.Not); + manager.add("bar", ds2); + + assertThat(manager.local).isTrue(); + assertThat(manager.listUnready).hasSize(2); + assertThat(manager.listReady).hasSize(0); + + var errors = manager.setupWithOrder(List.of("bar", "foo")); + + assertThat(manager.local).isTrue(); + assertThat(manager.listUnready).hasSize(2); + assertThat(manager.listReady).hasSize(0); + + assertThat(errors).hasSize(1); + assertThat(errors.get(0).index).isEqualTo(1); + assertThat(errors.get(0).name).isEqualTo("foo"); + assertThat(errors.get(0).err.toString()) + .isEqualTo( + "com.github.sttk.errs.Err { reason = com.github.sttk.sabi.AsyncGroup$RuntimeExceptionOccured RuntimeExceptionOccured[], file = AsyncGroupImpl.java, line = 58, cause = java.lang.RuntimeException }"); + } finally { + manager.close(); + } + } + + @Test + void setupWithOrderButDsIsNull() { + var logger = new ArrayList(); + + var manager = new DataSrcManager(true); + try { + manager.add("foo", null); + + assertThat(manager.local).isTrue(); + assertThat(manager.listUnready).hasSize(1); + assertThat(manager.listReady).hasSize(0); + + var errors = manager.setupWithOrder(List.of("xxx", "foo")); + assertThat(errors).hasSize(0); + + assertThat(manager.local).isTrue(); + assertThat(manager.listUnready).hasSize(0); + assertThat(manager.listReady).hasSize(0); + } finally { + manager.close(); + } + } + @Test void testCopyDsReadyToMap() { var logger = new ArrayList();