diff --git a/application/src/integrationTest/java/de/cotto/lndmanagej/controller/NodeControllerIT.java b/application/src/integrationTest/java/de/cotto/lndmanagej/controller/NodeControllerIT.java index 3c89a1ed..e05dd8f7 100644 --- a/application/src/integrationTest/java/de/cotto/lndmanagej/controller/NodeControllerIT.java +++ b/application/src/integrationTest/java/de/cotto/lndmanagej/controller/NodeControllerIT.java @@ -18,11 +18,13 @@ 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.CoopClosedChannelFixtures.CLOSED_CHANNEL; import static de.cotto.lndmanagej.model.CoopClosedChannelFixtures.CLOSED_CHANNEL_3; +import static de.cotto.lndmanagej.model.ForceClosingChannelFixtures.FORCE_CLOSING_CHANNEL_2; 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.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL_3; import static de.cotto.lndmanagej.model.NodeFixtures.ALIAS_2; import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_2; +import static de.cotto.lndmanagej.model.WaitingCloseChannelFixtures.WAITING_CLOSE_CHANNEL; import static org.hamcrest.core.Is.is; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -58,13 +60,19 @@ class NodeControllerIT { when(nodeService.getNode(PUBKEY_2)).thenReturn(new Node(PUBKEY_2, ALIAS_2, 0, true)); when(channelService.getOpenChannelsWith(PUBKEY_2)).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_2)); when(channelService.getClosedChannelsWith(PUBKEY_2)).thenReturn(Set.of(CLOSED_CHANNEL, CLOSED_CHANNEL_3)); + when(channelService.getWaitingCloseChannelsFor(PUBKEY_2)).thenReturn(Set.of(WAITING_CLOSE_CHANNEL)); + when(channelService.getForceClosingChannelsFor(PUBKEY_2)).thenReturn(Set.of(FORCE_CLOSING_CHANNEL_2)); List channelIds = List.of(CHANNEL_ID.toString(), CHANNEL_ID_2.toString()); List closedChannelIds = List.of(CHANNEL_ID.toString(), CHANNEL_ID_3.toString()); + List waitingCloseChannelIds = List.of(CHANNEL_ID.toString()); + List forceClosingChannelIds = List.of(CHANNEL_ID_2.toString()); mockMvc.perform(get(NODE_PREFIX + "/details")) .andExpect(jsonPath("$.node", is(PUBKEY_2.toString()))) .andExpect(jsonPath("$.alias", is(ALIAS_2))) .andExpect(jsonPath("$.channels", is(channelIds))) .andExpect(jsonPath("$.closedChannels", is(closedChannelIds))) + .andExpect(jsonPath("$.waitingCloseChannels", is(waitingCloseChannelIds))) + .andExpect(jsonPath("$.pendingForceClosingChannels", is(forceClosingChannelIds))) .andExpect(jsonPath("$.online", is(true))); } diff --git a/application/src/main/java/de/cotto/lndmanagej/controller/NodeController.java b/application/src/main/java/de/cotto/lndmanagej/controller/NodeController.java index 23865b39..b17f8358 100644 --- a/application/src/main/java/de/cotto/lndmanagej/controller/NodeController.java +++ b/application/src/main/java/de/cotto/lndmanagej/controller/NodeController.java @@ -18,6 +18,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; @RestController @@ -47,8 +48,10 @@ public class NodeController { return new NodeDetailsDto( pubkey, node.alias(), - getChannelIdsForPubkey(pubkey), - getClosedChannelIdsForPubkey(pubkey), + toSortedList(channelService.getOpenChannelsWith(pubkey)), + toSortedList(channelService.getClosedChannelsWith(pubkey)), + toSortedList(channelService.getWaitingCloseChannelsFor(pubkey)), + toSortedList(channelService.getForceClosingChannelsFor(pubkey)), node.online() ); } @@ -56,19 +59,12 @@ public class NodeController { @GetMapping("/open-channels") public ChannelsForNodeDto getOpenChannelIdsForPubkey(@PathVariable Pubkey pubkey) { mark("getOpenChannelIdsForPubkey"); - List channels = getChannelIdsForPubkey(pubkey); + List channels = toSortedList(channelService.getOpenChannelsWith(pubkey)); return new ChannelsForNodeDto(pubkey, channels); } - private List getChannelIdsForPubkey(Pubkey pubkey) { - return channelService.getOpenChannelsWith(pubkey).stream() - .map(Channel::getId) - .sorted() - .collect(Collectors.toList()); - } - - private List getClosedChannelIdsForPubkey(Pubkey pubkey) { - return channelService.getClosedChannelsWith(pubkey).stream() + private List toSortedList(Set channels) { + return channels.stream() .map(Channel::getId) .sorted() .collect(Collectors.toList()); diff --git a/application/src/main/java/de/cotto/lndmanagej/controller/dto/NodeDetailsDto.java b/application/src/main/java/de/cotto/lndmanagej/controller/dto/NodeDetailsDto.java index 034f66f1..c336c26a 100644 --- a/application/src/main/java/de/cotto/lndmanagej/controller/dto/NodeDetailsDto.java +++ b/application/src/main/java/de/cotto/lndmanagej/controller/dto/NodeDetailsDto.java @@ -12,6 +12,8 @@ public record NodeDetailsDto( String alias, List channels, List closedChannels, + List waitingCloseChannels, + List pendingForceClosingChannels, boolean online ) { } diff --git a/application/src/main/java/de/cotto/lndmanagej/service/ChannelService.java b/application/src/main/java/de/cotto/lndmanagej/service/ChannelService.java index 325550c0..911bc310 100644 --- a/application/src/main/java/de/cotto/lndmanagej/service/ChannelService.java +++ b/application/src/main/java/de/cotto/lndmanagej/service/ChannelService.java @@ -101,6 +101,18 @@ public class ChannelService { .collect(Collectors.toSet()); } + public Set getWaitingCloseChannelsFor(Pubkey peer) { + return getWaitingCloseChannels().stream() + .filter(c -> peer.equals(c.getRemotePubkey())) + .collect(Collectors.toSet()); + } + + public Set getForceClosingChannelsFor(Pubkey peer) { + return getForceClosingChannels().stream() + .filter(c -> peer.equals(c.getRemotePubkey())) + .collect(Collectors.toSet()); + } + public Set getAllChannelsWith(Pubkey peer) { return getAllLocalChannels() .filter(c -> peer.equals(c.getRemotePubkey())) diff --git a/application/src/test/java/de/cotto/lndmanagej/controller/NodeControllerTest.java b/application/src/test/java/de/cotto/lndmanagej/controller/NodeControllerTest.java index 3c6081c4..67d58662 100644 --- a/application/src/test/java/de/cotto/lndmanagej/controller/NodeControllerTest.java +++ b/application/src/test/java/de/cotto/lndmanagej/controller/NodeControllerTest.java @@ -20,12 +20,17 @@ 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.CoopClosedChannelFixtures.CLOSED_CHANNEL_2; import static de.cotto.lndmanagej.model.CoopClosedChannelFixtures.CLOSED_CHANNEL_3; +import static de.cotto.lndmanagej.model.ForceClosingChannelFixtures.FORCE_CLOSING_CHANNEL; +import static de.cotto.lndmanagej.model.ForceClosingChannelFixtures.FORCE_CLOSING_CHANNEL_2; +import static de.cotto.lndmanagej.model.ForceClosingChannelFixtures.FORCE_CLOSING_CHANNEL_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.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL_3; import static de.cotto.lndmanagej.model.NodeFixtures.ALIAS_2; import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY; import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_2; +import static de.cotto.lndmanagej.model.WaitingCloseChannelFixtures.WAITING_CLOSE_CHANNEL; +import static de.cotto.lndmanagej.model.WaitingCloseChannelFixtures.WAITING_CLOSE_CHANNEL_2; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.verify; @@ -55,7 +60,15 @@ class NodeControllerTest { @Test void getNodeDetails_no_channels() { - NodeDetailsDto expectedDetails = new NodeDetailsDto(PUBKEY_2, ALIAS_2, List.of(), List.of(), true); + NodeDetailsDto expectedDetails = new NodeDetailsDto( + PUBKEY_2, + ALIAS_2, + List.of(), + List.of(), + List.of(), + List.of(), + true + ); when(nodeService.getNode(PUBKEY_2)).thenReturn(new Node(PUBKEY_2, ALIAS_2, 0, true)); assertThat(nodeController.getDetails(PUBKEY_2)).isEqualTo(expectedDetails); @@ -67,11 +80,19 @@ class NodeControllerTest { when(nodeService.getNode(PUBKEY_2)).thenReturn(new Node(PUBKEY_2, ALIAS_2, 0, false)); when(channelService.getOpenChannelsWith(PUBKEY_2)).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_3)); when(channelService.getClosedChannelsWith(PUBKEY_2)).thenReturn(Set.of(CLOSED_CHANNEL_2, CLOSED_CHANNEL_3)); + when(channelService.getWaitingCloseChannelsFor(PUBKEY_2)).thenReturn( + Set.of(WAITING_CLOSE_CHANNEL, WAITING_CLOSE_CHANNEL_2) + ); + when(channelService.getForceClosingChannelsFor(PUBKEY_2)).thenReturn( + Set.of(FORCE_CLOSING_CHANNEL, FORCE_CLOSING_CHANNEL_2, FORCE_CLOSING_CHANNEL_3) + ); NodeDetailsDto expectedDetails = new NodeDetailsDto( PUBKEY_2, ALIAS_2, List.of(CHANNEL_ID, CHANNEL_ID_3), List.of(CHANNEL_ID_2, CHANNEL_ID_3), + List.of(CHANNEL_ID, CHANNEL_ID_2), + List.of(CHANNEL_ID, CHANNEL_ID_2, CHANNEL_ID_3), false ); diff --git a/application/src/test/java/de/cotto/lndmanagej/service/ChannelServiceTest.java b/application/src/test/java/de/cotto/lndmanagej/service/ChannelServiceTest.java index 820ad767..213c5023 100644 --- a/application/src/test/java/de/cotto/lndmanagej/service/ChannelServiceTest.java +++ b/application/src/test/java/de/cotto/lndmanagej/service/ChannelServiceTest.java @@ -145,6 +145,38 @@ class ChannelServiceTest { .containsExactlyInAnyOrder(CLOSED_CHANNEL, CLOSED_CHANNEL_2); } + @Test + void getWaitingCloseChannelsWith_by_pubkey() { + when(grpcChannels.getWaitingCloseChannels()).thenReturn(Set.of(WAITING_CLOSE_CHANNEL, WAITING_CLOSE_CHANNEL_2)); + assertThat(channelService.getWaitingCloseChannelsFor(PUBKEY_2)) + .containsExactlyInAnyOrder(WAITING_CLOSE_CHANNEL, WAITING_CLOSE_CHANNEL_2); + } + + @Test + void getWaitingCloseChannelsWith_ignores_channel_to_other_node() { + when(grpcChannels.getWaitingCloseChannels()).thenReturn( + Set.of(WAITING_CLOSE_CHANNEL, WAITING_CLOSE_CHANNEL_2, WAITING_CLOSE_CHANNEL_TO_NODE_3) + ); + assertThat(channelService.getWaitingCloseChannelsFor(PUBKEY_2)) + .containsExactlyInAnyOrder(WAITING_CLOSE_CHANNEL, WAITING_CLOSE_CHANNEL_2); + } + + @Test + void getForceClosingChannelsWith_by_pubkey() { + when(grpcChannels.getForceClosingChannels()).thenReturn(Set.of(FORCE_CLOSING_CHANNEL, FORCE_CLOSING_CHANNEL_2)); + assertThat(channelService.getForceClosingChannelsFor(PUBKEY_2)) + .containsExactlyInAnyOrder(FORCE_CLOSING_CHANNEL, FORCE_CLOSING_CHANNEL_2); + } + + @Test + void getForceClosingChannelsWith_ignores_channel_to_other_node() { + when(grpcChannels.getForceClosingChannels()).thenReturn( + Set.of(FORCE_CLOSING_CHANNEL, FORCE_CLOSING_CHANNEL_2, FORCE_CLOSING_CHANNEL_TO_NODE_3) + ); + assertThat(channelService.getForceClosingChannelsFor(PUBKEY_2)) + .containsExactlyInAnyOrder(FORCE_CLOSING_CHANNEL, FORCE_CLOSING_CHANNEL_2); + } + @Test void getOpenChannels() { when(grpcChannels.getChannels()).thenReturn(Set.of(LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_2));