Add uptime command
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Mon, 23 Feb 2015 06:14:54 +0000 (07:14 +0100)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Mon, 23 Feb 2015 06:14:54 +0000 (07:14 +0100)
src/main/java/net/pterodactylus/xdcc/core/Core.java
src/main/java/net/pterodactylus/xdcc/data/ConnectedNetwork.java
src/main/java/net/pterodactylus/xdcc/ui/stdin/CommandReader.java
src/main/java/net/pterodactylus/xdcc/ui/stdin/UptimeCommand.java [new file with mode: 0644]
src/test/java/net/pterodactylus/xdcc/ui/stdin/StatsCommandTest.java
src/test/java/net/pterodactylus/xdcc/ui/stdin/UptimeCommandTest.java [new file with mode: 0644]

index bfad867..fab43ab 100644 (file)
@@ -30,6 +30,8 @@ import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.time.Duration;
+import java.time.Instant;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
@@ -110,6 +112,7 @@ public class Core extends AbstractExecutionThreadService {
        /** The logger. */
        private static final Logger logger = Logger.getLogger(Core.class.getName());
 
+       private final Instant startup = Instant.now();
        private final Object syncObject = new Object();
        /** The event bus. */
        private final EventBus eventBus;
@@ -196,8 +199,11 @@ public class Core extends AbstractExecutionThreadService {
                        Network network = entry.getKey();
                        Collection<Bot> bots = networkBots.row(network).values();
                        int packCount = bots.stream().mapToInt((bot) -> bot.packs().size()).reduce((a, b) -> a + b).orElse(0);
-                       return new ConnectedNetwork(network, entry.getValue().hostname(),
-                                       entry.getValue().port(), entry.getValue().nickname(),
+                       Connection connection = entry.getValue();
+                       return new ConnectedNetwork(network, connection.hostname(),
+                                       connection.port(),
+                                       connection.getUptime().get(),
+                                       connection.nickname(),
                                        channels.stream()
                                                        .filter((channel) -> channel.network()
                                                                        .equals(network))
@@ -258,6 +264,10 @@ public class Core extends AbstractExecutionThreadService {
                return downloads.values();
        }
 
+       public Duration getUptime() {
+               return Duration.between(startup, Instant.now());
+       }
+
        //
        // ACTIONS
        //
index 183f1f3..49e2d5b 100644 (file)
@@ -1,5 +1,6 @@
 package net.pterodactylus.xdcc.data;
 
+import java.time.Duration;
 import java.util.Collection;
 
 /**
@@ -12,6 +13,7 @@ public class ConnectedNetwork {
        private final Network network;
        private final String hostname;
        private final int port;
+       private final Duration uptime;
        private final String nickname;
        private final Collection<String> channels;
        private final Collection<String> forcedChannels;
@@ -19,11 +21,12 @@ public class ConnectedNetwork {
        private final int packCount;
 
        public ConnectedNetwork(Network network, String hostname, int port,
-                       String nickname, Collection<String> channels,
+                       Duration uptime, String nickname, Collection<String> channels,
                        Collection<String> forcedChannels, int botCount, int packCount) {
                this.network = network;
                this.hostname = hostname;
                this.port = port;
+               this.uptime = uptime;
                this.nickname = nickname;
                this.channels = channels;
                this.forcedChannels = forcedChannels;
@@ -35,6 +38,10 @@ public class ConnectedNetwork {
                return network;
        }
 
+       public Duration getUptime() {
+               return uptime;
+       }
+
        public String getHostname() {
                return hostname;
        }
index 2d0a352..66447b0 100644 (file)
@@ -93,6 +93,7 @@ public class CommandReader extends AbstractExecutionThreadService {
                commandBuilder.add(new FailedDownloadsCommand(failedDownloads));
                commandBuilder.add(new RestartCommand(core, failedDownloads));
                commandBuilder.add(new ResearchCommand(core));
+               commandBuilder.add(new UptimeCommand(core));
                commands = commandBuilder.build();
        }
 
diff --git a/src/main/java/net/pterodactylus/xdcc/ui/stdin/UptimeCommand.java b/src/main/java/net/pterodactylus/xdcc/ui/stdin/UptimeCommand.java
new file mode 100644 (file)
index 0000000..56188ec
--- /dev/null
@@ -0,0 +1,71 @@
+package net.pterodactylus.xdcc.ui.stdin;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.time.Duration;
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import net.pterodactylus.xdcc.core.Core;
+import net.pterodactylus.xdcc.data.ConnectedNetwork;
+
+/**
+ * {@link Command} that writes uptime information.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class UptimeCommand implements Command {
+
+       private final DateTimeFormatter formatter = DateTimeFormatter.RFC_1123_DATE_TIME;
+       private final Core core;
+
+       public UptimeCommand(Core core) {
+               this.core = core;
+       }
+
+       @Override
+       public String getName() {
+               return "uptime";
+       }
+
+       @Override
+       public Collection<String> getAliases() {
+               return Collections.emptySet();
+       }
+
+       @Override
+       public State execute(State state, List<String> parameters, Writer outputWriter)
+       throws IOException {
+               OffsetDateTime now = OffsetDateTime.now();
+               outputWriter.write(String.format("Core running since %s, %s ago.\n",
+                               formatter.format(core.getUptime().subtractFrom(now)),
+                               formatTime(core.getUptime())));
+               for (ConnectedNetwork network : core.connectedNetworks()) {
+                       outputWriter.write(String.format("%s connected since %s, %s ago.\n",
+                                       network.getNetwork().name(),
+                                       formatter.format(network.getUptime().subtractFrom(now)),
+                                       formatTime(network.getUptime())));
+               }
+               return state;
+       }
+
+       private String formatTime(Duration uptime) {
+               long uptimeSeconds = uptime.getSeconds();
+               long seconds = uptimeSeconds % 60;
+               long minutes = (uptimeSeconds / 60) % 60;
+               long hours = (uptimeSeconds / (60 * 60)) % 24;
+               long days = (uptimeSeconds / (60 * 60 * 24)) % 7;
+               long weeks = (uptimeSeconds / (60 * 60 * 24 * 7));
+               String uptimeString = Stream
+                               .of(weeks + "w", days + "d", hours + "h", minutes + "m", seconds + "s")
+                               .filter(v -> !v.startsWith("0"))
+                               .collect(Collectors.joining(" "));
+               return uptimeString.isEmpty() ? "0s" : uptimeString;
+       }
+
+}
index c1f0abc..efbdde3 100644 (file)
@@ -10,6 +10,7 @@ import static org.mockito.Mockito.when;
 
 import java.io.IOException;
 import java.io.StringWriter;
+import java.time.Duration;
 
 import net.pterodactylus.xdcc.core.Core;
 import net.pterodactylus.xdcc.data.ConnectedNetwork;
@@ -34,6 +35,7 @@ public class StatsCommandTest {
                                builder("TestNet").build(),
                                "irc.test.net",
                                6667,
+                               Duration.ofMinutes(1),
                                "Nickname1",
                                asList("#channel1", "#channel2"),
                                emptyList(),
@@ -44,6 +46,7 @@ public class StatsCommandTest {
                                builder("DummyNet").build(),
                                "irc.dummy.net",
                                6789,
+                               Duration.ofMinutes(1),
                                "Nickname2",
                                asList("#dummy1", "#dummy2"),
                                asList("#foo", "#bar"),
@@ -54,6 +57,7 @@ public class StatsCommandTest {
                                builder("FooNet").build(),
                                "irc.foo.net",
                                7000,
+                               Duration.ofMinutes(1),
                                "Nickname3",
                                emptyList(),
                                emptyList(),
@@ -64,6 +68,7 @@ public class StatsCommandTest {
                                builder("BarNet").build(),
                                "irc.bar.net",
                                7001,
+                               Duration.ofMinutes(1),
                                "Nickname4",
                                emptyList(),
                                asList("#foo", "#bar"),
diff --git a/src/test/java/net/pterodactylus/xdcc/ui/stdin/UptimeCommandTest.java b/src/test/java/net/pterodactylus/xdcc/ui/stdin/UptimeCommandTest.java
new file mode 100644 (file)
index 0000000..1f4b83a
--- /dev/null
@@ -0,0 +1,77 @@
+package net.pterodactylus.xdcc.ui.stdin;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.Collections;
+
+import net.pterodactylus.xdcc.core.Core;
+import net.pterodactylus.xdcc.data.ConnectedNetwork;
+import net.pterodactylus.xdcc.data.Network;
+
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/**
+ * Unit test for {@link UptimeCommand}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class UptimeCommandTest {
+
+       private final Core core = Mockito.mock(Core.class);
+       private final UptimeCommand uptimeCommand = new UptimeCommand(core);
+       private final State state = Mockito.mock(State.class);
+       private final Writer writer = new StringWriter();
+
+       @Test
+       public void commandNameIsCorrect() {
+           MatcherAssert.assertThat(uptimeCommand.getName(), Matchers.is("uptime"));
+       }
+
+       @Test
+       public void aliasesAreEmpty() {
+               MatcherAssert.assertThat(uptimeCommand.getAliases(), Matchers.empty());
+       }
+
+       @Test
+       public void connectionUptimeIsWritten() throws IOException {
+               Mockito.when(core.getUptime()).thenReturn(createDuration(1, 2, 3, 4, 5));
+               uptimeCommand.execute(state, Collections.<String>emptyList(), writer);
+               MatcherAssert.assertThat(writer.toString(), Matchers.containsString("1w 2d 3h 4m 5s"));
+       }
+
+       @Test
+       public void connectionUptimeIsWrittenIfItIsZeroSeconds() throws IOException {
+               Mockito.when(core.getUptime()).thenReturn(createDuration(0, 0, 0, 0, 0));
+               uptimeCommand.execute(state, Collections.<String>emptyList(), writer);
+               MatcherAssert.assertThat(writer.toString(), Matchers.containsString("0s"));
+       }
+
+       @Test
+       public void networkUptimeIsWritten() throws IOException {
+               Mockito.when(core.getUptime()).thenReturn(createDuration(1, 2, 3, 4, 5));
+               ConnectedNetwork connectedNetwork = Mockito.mock(ConnectedNetwork.class);
+               Network network = Mockito.mock(Network.class);
+               Mockito.when(network.name()).thenReturn("Test");
+               Mockito.when(connectedNetwork.getNetwork()).thenReturn(network);
+               Mockito.when(connectedNetwork.getUptime()).thenReturn(createDuration(2, 3, 4, 5, 6));
+               Mockito.when(core.connectedNetworks()).thenReturn(Arrays.asList(connectedNetwork));
+               uptimeCommand.execute(state, Collections.<String>emptyList(), writer);
+               MatcherAssert.assertThat(writer.toString(), Matchers.containsString("2w 3d 4h 5m 6s"));
+       }
+
+       private Duration createDuration(int weeks, int days, int hours, int minutes, int seconds) {
+               return Duration.ofSeconds(
+                               weeks * (7 * 24 * 60 * 60) +
+                                               days * (24 * 60 * 60) +
+                                               hours * (60 * 60) +
+                                               minutes * 60 +
+                                               seconds);
+       }
+
+}