From 4fd96e740f718a81be4730c5f81fedbbf1560cb5 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 21 Mar 2023 22:01:34 +0100 Subject: [PATCH] do not start inner transaction for transformation throwing in an inner transaction will fail the entire transaction even if the exception is caught in the outer transaction --- .../android/xmpp/ArchivePagingTest.java | 39 +++++++++++++++++++ .../android/database/dao/MessageDao.java | 1 - .../android/transformer/Transformer.java | 2 + 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/app/src/androidTest/java/im/conversations/android/xmpp/ArchivePagingTest.java b/app/src/androidTest/java/im/conversations/android/xmpp/ArchivePagingTest.java index 603b2eebb..e96b1899a 100644 --- a/app/src/androidTest/java/im/conversations/android/xmpp/ArchivePagingTest.java +++ b/app/src/androidTest/java/im/conversations/android/xmpp/ArchivePagingTest.java @@ -4,6 +4,7 @@ import static org.hamcrest.Matchers.*; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import im.conversations.android.database.model.Account; import im.conversations.android.database.model.StanzaId; @@ -143,6 +144,44 @@ public class ArchivePagingTest extends BaseTransformationTest { MatcherAssert.assertThat(rangesSecondAttempt, contains(new Range(Range.Order.NORMAL, "6"))); } + @Test + public void liveMessageQuerySubmitTwiceWithDuplicates() + throws ExecutionException, InterruptedException { + final var stub2 = new StubMessage(2); + transformer.transform(stub2.messageTransformation(), stub2.stanzaId()); + + final var ranges = database.archiveDao().resetLivePage(account(), ACCOUNT); + Assert.assertEquals(2, ranges.size()); + MatcherAssert.assertThat( + ranges, + contains(new Range(Range.Order.REVERSE, "2"), new Range(Range.Order.NORMAL, "2"))); + + final var account = account(); + + final var transformer = + new Transformer(account, ApplicationProvider.getApplicationContext(), database); + + transformer.transform( + Collections.emptyList(), + ACCOUNT, + new Range(Range.Order.REVERSE, "2"), + new ArchiveManager.QueryResult(true, Page.emptyWithCount("2", null)), + true); + transformer.transform( + ImmutableList.of(stub2.messageTransformation()), + ACCOUNT, + new Range(Range.Order.NORMAL, "2"), + new ArchiveManager.QueryResult(false, new Page("3", "4", 2)), + false); + + transformer.transform( + Collections.emptyList(), + ACCOUNT, + new Range(Range.Order.NORMAL, "4"), + new ArchiveManager.QueryResult(true, new Page("5", "6", 2)), + false); + } + private Account account() throws ExecutionException, InterruptedException { return this.database.accountDao().getEnabledAccount(ACCOUNT).get(); } diff --git a/app/src/main/java/im/conversations/android/database/dao/MessageDao.java b/app/src/main/java/im/conversations/android/database/dao/MessageDao.java index 8b7e57c4a..115520776 100644 --- a/app/src/main/java/im/conversations/android/database/dao/MessageDao.java +++ b/app/src/main/java/im/conversations/android/database/dao/MessageDao.java @@ -72,7 +72,6 @@ public abstract class MessageDao { // it might return something that was previously a stub (message that only has reactions or // corrections but no original content). but in the process of invoking this method the stub // will be upgraded to an original message (missing information filled in) - @Transaction public MessageIdentifier getOrCreateMessage( ChatIdentifier chatIdentifier, final MessageTransformation transformation) { final MessageIdentifier messageIdentifier = diff --git a/app/src/main/java/im/conversations/android/transformer/Transformer.java b/app/src/main/java/im/conversations/android/transformer/Transformer.java index d0e8f0e35..8f17b007f 100644 --- a/app/src/main/java/im/conversations/android/transformer/Transformer.java +++ b/app/src/main/java/im/conversations/android/transformer/Transformer.java @@ -105,6 +105,8 @@ public class Transformer { */ private boolean transform( final ConversationsDatabase database, final MessageTransformation transformation) { + Preconditions.checkState( + database.inTransaction(), "Transformations must be run from a transaction"); final var remote = transformation.remote; final var messageType = transformation.type; final var muc = transformation.getExtension(MucUser.class);