From 8186a342faaffb18d3f805c8bafa66948e6ecd0d Mon Sep 17 00:00:00 2001 From: Carsten Otto Date: Tue, 16 Nov 2021 22:18:13 +0100 Subject: [PATCH] download transactions for open channels in background --- .../service/TransactionBackgroundLoader.java | 30 +++++++ .../TransactionBackgroundLoaderTest.java | 80 +++++++++++++++++++ .../service/TransactionService.java | 8 ++ .../service/TransactionServiceTest.java | 14 ++++ 4 files changed, 132 insertions(+) create mode 100644 application/src/main/java/de/cotto/lndmanagej/service/TransactionBackgroundLoader.java create mode 100644 application/src/test/java/de/cotto/lndmanagej/service/TransactionBackgroundLoaderTest.java diff --git a/application/src/main/java/de/cotto/lndmanagej/service/TransactionBackgroundLoader.java b/application/src/main/java/de/cotto/lndmanagej/service/TransactionBackgroundLoader.java new file mode 100644 index 00000000..2628b268 --- /dev/null +++ b/application/src/main/java/de/cotto/lndmanagej/service/TransactionBackgroundLoader.java @@ -0,0 +1,30 @@ +package de.cotto.lndmanagej.service; + +import de.cotto.lndmanagej.model.Channel; +import de.cotto.lndmanagej.model.ChannelPoint; +import de.cotto.lndmanagej.transactions.service.TransactionService; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.concurrent.TimeUnit; + +@Component +public class TransactionBackgroundLoader { + private final ChannelService channelService; + private final TransactionService transactionService; + + public TransactionBackgroundLoader(ChannelService channelService, TransactionService transactionService) { + this.channelService = channelService; + this.transactionService = transactionService; + } + + @Scheduled(fixedDelay = 5, timeUnit = TimeUnit.MINUTES) + public void loadTransactionForOneChannel() { + channelService.getOpenChannels().stream() + .map(Channel::getChannelPoint) + .map(ChannelPoint::getTransactionHash) + .filter(transactionService::isUnknown) + .findAny() + .ifPresent(transactionService::getTransaction); + } +} diff --git a/application/src/test/java/de/cotto/lndmanagej/service/TransactionBackgroundLoaderTest.java b/application/src/test/java/de/cotto/lndmanagej/service/TransactionBackgroundLoaderTest.java new file mode 100644 index 00000000..bdcfdaa5 --- /dev/null +++ b/application/src/test/java/de/cotto/lndmanagej/service/TransactionBackgroundLoaderTest.java @@ -0,0 +1,80 @@ +package de.cotto.lndmanagej.service; + +import de.cotto.lndmanagej.model.LocalOpenChannel; +import de.cotto.lndmanagej.transactions.service.TransactionService; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Set; + +import static de.cotto.lndmanagej.model.BalanceInformationFixtures.BALANCE_INFORMATION; +import static de.cotto.lndmanagej.model.ChannelFixtures.CAPACITY; +import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID; +import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID_2; +import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID_3; +import static de.cotto.lndmanagej.model.ChannelPointFixtures.CHANNEL_POINT; +import static de.cotto.lndmanagej.model.ChannelPointFixtures.CHANNEL_POINT_2; +import static de.cotto.lndmanagej.model.ChannelPointFixtures.CHANNEL_POINT_3; +import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL; +import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL_2; +import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY; +import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_2; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class TransactionBackgroundLoaderTest { + @InjectMocks + private TransactionBackgroundLoader transactionBackgroundLoader; + + @Mock + private TransactionService transactionService; + + @Mock + private ChannelService channelService; + + @Test + void update_no_channel() { + transactionBackgroundLoader.loadTransactionForOneChannel(); + verify(transactionService, never()).getTransaction(any()); + } + + @Test + void update_all_known() { + when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_2)); + when(transactionService.isUnknown(any())).thenReturn(false); + transactionBackgroundLoader.loadTransactionForOneChannel(); + verify(transactionService, never()).getTransaction(any()); + } + + @Test + void update_all_unknown() { + when(channelService.getOpenChannels()).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_2)); + when(transactionService.isUnknown(any())).thenReturn(true); + transactionBackgroundLoader.loadTransactionForOneChannel(); + verify(transactionService, times(1)).getTransaction(any()); + } + + @Test + void update_one_unknown() { + LocalOpenChannel channel1 = + new LocalOpenChannel(CHANNEL_ID, CHANNEL_POINT, CAPACITY, PUBKEY, PUBKEY_2, BALANCE_INFORMATION); + LocalOpenChannel channel2 = + new LocalOpenChannel(CHANNEL_ID_2, CHANNEL_POINT_2, CAPACITY, PUBKEY, PUBKEY_2, BALANCE_INFORMATION); + LocalOpenChannel channel3 = + new LocalOpenChannel(CHANNEL_ID_3, CHANNEL_POINT_3, CAPACITY, PUBKEY, PUBKEY_2, BALANCE_INFORMATION); + when(channelService.getOpenChannels()).thenReturn(Set.of(channel1, channel2, channel3)); + String unknownHash = CHANNEL_POINT_3.getTransactionHash(); + when(transactionService.isUnknown(unknownHash)).thenReturn(true); + + transactionBackgroundLoader.loadTransactionForOneChannel(); + + verify(transactionService, times(1)).getTransaction(unknownHash); + } +} \ No newline at end of file diff --git a/transactions/src/main/java/de/cotto/lndmanagej/transactions/service/TransactionService.java b/transactions/src/main/java/de/cotto/lndmanagej/transactions/service/TransactionService.java index 9db5b47c..e83d45cb 100644 --- a/transactions/src/main/java/de/cotto/lndmanagej/transactions/service/TransactionService.java +++ b/transactions/src/main/java/de/cotto/lndmanagej/transactions/service/TransactionService.java @@ -28,6 +28,14 @@ public class TransactionService { return downloadAndPersist(transactionHash); } + public boolean isKnown(String transactionHash) { + return transactionDao.getTransaction(transactionHash).isPresent(); + } + + public boolean isUnknown(String transactionHash) { + return !isKnown(transactionHash); + } + private Optional downloadAndPersist(String transactionHash) { Optional optionalTransaction = transactionProvider.get(transactionHash); optionalTransaction.ifPresent(transactionDao::saveTransaction); diff --git a/transactions/src/test/java/de/cotto/lndmanagej/transactions/service/TransactionServiceTest.java b/transactions/src/test/java/de/cotto/lndmanagej/transactions/service/TransactionServiceTest.java index 3e7a66d8..f80e2a1c 100644 --- a/transactions/src/test/java/de/cotto/lndmanagej/transactions/service/TransactionServiceTest.java +++ b/transactions/src/test/java/de/cotto/lndmanagej/transactions/service/TransactionServiceTest.java @@ -57,4 +57,18 @@ class TransactionServiceTest { assertThat(transactionService.getTransaction(TRANSACTION_HASH)).isEmpty(); verify(transactionDao, never()).saveTransaction(any()); } + + @Test + void isKnown_false() { + when(transactionDao.getTransaction(TRANSACTION_HASH)).thenReturn(Optional.empty()); + assertThat(transactionService.isKnown(TRANSACTION_HASH)).isFalse(); + assertThat(transactionService.isUnknown(TRANSACTION_HASH)).isTrue(); + } + + @Test + void isKnown_true() { + when(transactionDao.getTransaction(TRANSACTION_HASH)).thenReturn(Optional.of(TRANSACTION)); + assertThat(transactionService.isKnown(TRANSACTION_HASH)).isTrue(); + assertThat(transactionService.isUnknown(TRANSACTION_HASH)).isFalse(); + } } \ No newline at end of file