diff --git a/pom.xml b/pom.xml
index b3727ce..7b0a8c1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
cf.maybelambda
fedora-setup-script
- 3.0.4
+ 3.0.5
21
@@ -51,7 +51,7 @@
true
- cf.maybelambda.fedora.PostInstallUpdater
+ cf.maybelambda.fedora.Main
diff --git a/src/main/java/cf/maybelambda/fedora/Main.java b/src/main/java/cf/maybelambda/fedora/Main.java
new file mode 100644
index 0000000..6c9491b
--- /dev/null
+++ b/src/main/java/cf/maybelambda/fedora/Main.java
@@ -0,0 +1,99 @@
+package cf.maybelambda.fedora;
+
+import static cf.maybelambda.fedora.ConsoleIOHelper.GREEN;
+import static cf.maybelambda.fedora.ConsoleIOHelper.RED;
+import static cf.maybelambda.fedora.ConsoleIOHelper.color;
+import static cf.maybelambda.fedora.ConsoleIOHelper.confirm;
+import static cf.maybelambda.fedora.ConsoleIOHelper.promptForExclusions;
+import static java.util.Arrays.asList;
+
+import java.util.List;
+import java.util.Scanner;
+
+public class Main {
+ static List CMD_RPM_IMPORT = asList("sudo", "rpm", "--import");
+ static List CMD_DNF_INST_REPOS = asList("sudo", "dnf", "install", "-y");
+ static List CMD_DNF_INST = asList("sudo", "dnf", "--refresh", "install", "-y");
+ static List CMD_DNF_RM = asList("sudo", "dnf", "remove", "-y", "--noautoremove");
+ static List CMD_DNF_MARK = asList("sudo", "dnf", "mark", "user", "flatpak"); // single arg appended to cmd
+ static List CMD_DNF_AUTORM = asList("sudo", "dnf", "autoremove", "-y");
+ static List CMD_FLATPAK_REMOTE_ADD = asList("sudo", "flatpak", "remote-add", "--if-not-exists");
+ static List CMD_FLATPAK_INST = asList("flatpak", "install", "-y");
+ static List CMD_GETENT = asList("getent", "group");
+ static List CMD_ADD_GROUP = asList("sudo", "groupadd");
+ static List CMD_ADD_USER_TO_GROUP = asList("sudo", "usermod", "-aG");
+ static List CMD_SYSTEMCTL_ENABLE = asList("sudo", "systemctl", "enable", "--now", "cockpit.socket"); // single arg appended to cmd
+
+ public static void main(String[] args) {
+ run(args, new PostInstallUpdater());
+ }
+
+ static void run(String[] args, PostInstallUpdater updater) {
+ if (asList(args).contains("-h") || asList(args).contains("--help")) {
+ ConsoleIOHelper.printHelp();
+ return;
+ }
+
+ System.out.println(color("]|I{•------» Fedora Setup Script «------•}I|[\n", GREEN));
+
+ List dnfInstallPackages = ConfigManager.getDnfInstallPackages();
+ List dnfRemovePackages = ConfigManager.getDnfRemovePackages();
+ List flatpakInstallPackages = ConfigManager.getFlatpakInstallPackages();
+ Scanner scanner = new Scanner(System.in);
+
+ updater.setDryRun(asList(args).contains("--dry-run"));
+ if (updater.isDryRun()) {
+ System.out.println(color("---[Dry Run Mode] Shell Commands will not be executed.---\n", RED));
+ }
+
+ if (confirm(scanner, "Install RPMFusion repos?")) {
+ for (String key : ConfigManager.getRPMFusionGpgKeys()) {
+ updater.runCommand(CMD_RPM_IMPORT, asList(key));
+ }
+
+ List repos = ConfigManager.getRPMFusionRepos();
+ updater.runCommand(CMD_DNF_INST_REPOS, repos);
+ }
+
+ if (confirm(scanner, "Install additional packages with DNF?")) {
+ List filtered = promptForExclusions(dnfInstallPackages, scanner);
+ updater.runCommand(CMD_DNF_INST, filtered);
+ }
+
+ if (confirm(scanner, "Remove all DNF packages marked for removal?")) {
+ List filtered = promptForExclusions(dnfRemovePackages, scanner);
+ updater.runCommand(CMD_DNF_RM, filtered);
+ updater.runCommand(CMD_DNF_MARK, asList());
+ updater.runCommand(CMD_DNF_AUTORM, asList());
+ }
+
+ if (confirm(scanner, "Install Flatpak apps?")) {
+ String name = ConfigManager.getFlatpakRemoteName();
+ String url = ConfigManager.getFlatpakRemoteUrl();
+ updater.runCommand(CMD_FLATPAK_REMOTE_ADD, asList(name, url));
+
+ List filtered = promptForExclusions(flatpakInstallPackages, scanner);
+ filtered.addFirst(name);
+ updater.runCommand(CMD_FLATPAK_INST, filtered);
+ }
+
+ if (confirm(scanner, "Ensure admin groups exist and add current user to them?")) {
+ String user = System.getProperty("user.name");
+ for (String group : ConfigManager.getAdminGroups()) {
+ int exit = updater.runCommand(CMD_GETENT, asList(group));
+ boolean groupExists = (exit == 0);
+ if (!groupExists) {
+ System.out.println("Group '" + group + "' does not exist. Creating...");
+ updater.runCommand(CMD_ADD_GROUP, asList(group));
+ }
+ updater.runCommand(CMD_ADD_USER_TO_GROUP, asList(group, user));
+ }
+ }
+
+ if (confirm(scanner, "Enable and start cockpit.socket service?")) {
+ updater.runCommand(CMD_SYSTEMCTL_ENABLE, asList());
+ }
+
+ System.out.println(color("\n.o0×X×0o. All actions completed. Goodbye. .o0×X×0o.", GREEN));
+ }
+}
diff --git a/src/main/java/cf/maybelambda/fedora/PostInstallUpdater.java b/src/main/java/cf/maybelambda/fedora/PostInstallUpdater.java
index 5712f18..30a7de8 100644
--- a/src/main/java/cf/maybelambda/fedora/PostInstallUpdater.java
+++ b/src/main/java/cf/maybelambda/fedora/PostInstallUpdater.java
@@ -1,135 +1,33 @@
package cf.maybelambda.fedora;
+import static cf.maybelambda.fedora.ConsoleIOHelper.BLUE;
+import static cf.maybelambda.fedora.ConsoleIOHelper.YELLOW;
+import static cf.maybelambda.fedora.ConsoleIOHelper.color;
+import static java.util.stream.Stream.concat;
+
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
-import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
-import java.util.Scanner;
-
-import static cf.maybelambda.fedora.ConsoleIOHelper.BLUE;
-import static cf.maybelambda.fedora.ConsoleIOHelper.GREEN;
-import static cf.maybelambda.fedora.ConsoleIOHelper.RED;
-import static cf.maybelambda.fedora.ConsoleIOHelper.YELLOW;
-import static cf.maybelambda.fedora.ConsoleIOHelper.color;
-import static cf.maybelambda.fedora.ConsoleIOHelper.confirm;
-import static cf.maybelambda.fedora.ConsoleIOHelper.promptForExclusions;
public class PostInstallUpdater {
- private static boolean dryRun;
-
- public static void main(String[] args) {
- if (Arrays.asList(args).contains("-h") || Arrays.asList(args).contains("--help")) {
- ConsoleIOHelper.printHelp();
- return;
- }
-
- List dnfInstallPackages = ConfigManager.getDnfInstallPackages();
- List dnfRemovePackages = ConfigManager.getDnfRemovePackages();
- List flatpakInstallPackages = ConfigManager.getFlatpakInstallPackages();
- Scanner scanner = new Scanner(System.in);
-
- System.out.println(color("]|I{•------» Fedora Setup Script «------•}I|[\n", GREEN));
- setDryRun(Arrays.asList(args).contains("--dry-run"));
- if (isDryRun()) {
- System.out.println(color("---[Dry Run Mode] Shell Commands will not be executed.---\n", RED));
- }
-
- if (confirm(scanner, "Install RPMFusion repos?")) {
- for (String key : ConfigManager.getRPMFusionGpgKeys()) {
- runCommand(new String[]{"sudo", "rpm", "--import", key});
- }
-
- List repos = ConfigManager.getRPMFusionRepos();
- String[] cmd = new String[repos.size() + 4];
- cmd[0] = "sudo";
- cmd[1] = "dnf";
- cmd[2] = "install";
- cmd[3] = "-y";
- for (int i = 0; i < repos.size(); i++) {
- cmd[4 + i] = repos.get(i);
- }
- runCommand(cmd);
- }
-
- if (confirm(scanner, "Install additional packages with DNF?")) {
- List filtered = promptForExclusions(dnfInstallPackages, scanner);
- String[] cmd = new String[filtered.size() + 5];
- cmd[0] = "sudo";
- cmd[1] = "dnf";
- cmd[2] = "--refresh";
- cmd[3] = "install";
- cmd[4] = "-y";
- for (int i = 0; i < filtered.size(); i++) {
- cmd[5 + i] = filtered.get(i);
- }
- runCommand(cmd);
- }
-
- if (confirm(scanner, "Remove all DNF packages marked for removal?")) {
- List filtered = promptForExclusions(dnfRemovePackages, scanner);
- String[] cmd = new String[filtered.size() + 4];
- cmd[0] = "sudo";
- cmd[1] = "dnf";
- cmd[2] = "remove";
- cmd[3] = "-y";
- for (int i = 0; i < filtered.size(); i++) {
- cmd[4 + i] = filtered.get(i);
- }
- runCommand(cmd);
- runCommand(new String[]{"sudo", "dnf", "autoremove", "-y"});
- }
-
- if (confirm(scanner, "Install Flatpak apps?")) {
- String name = ConfigManager.getFlatpakRemoteName();
- String url = ConfigManager.getFlatpakRemoteUrl();
- runCommand(new String[]{"sudo", "flatpak", "remote-add", "--if-not-exists", name, url});
- List filtered = promptForExclusions(flatpakInstallPackages, scanner);
- String[] cmd = new String[filtered.size() + 4];
- cmd[0] = "flatpak";
- cmd[1] = "install";
- cmd[2] = "-y";
- cmd[3] = name;
- for (int i = 0; i < filtered.size(); i++) {
- cmd[4 + i] = filtered.get(i);
- }
- runCommand(cmd);
- }
-
- if (confirm(scanner, "Ensure admin groups exist and add current user to them?")) {
- String user = System.getProperty("user.name");
- for (String group : ConfigManager.getAdminGroups()) {
- int exit = runCommand(new String[]{"getent", "group", group});
- boolean groupExists = (exit == 0);
- if (!groupExists) {
- System.out.println("Group '" + group + "' does not exist. Creating...");
- runCommand(new String[]{"sudo", "groupadd", group});
- }
- runCommand(new String[]{"sudo", "usermod", "-aG", group, user});
- }
- }
-
- if (confirm(scanner, "Enable and start cockpit.socket service?")) {
- runCommand(new String[]{"sudo", "systemctl", "enable", "--now", "cockpit.socket"});
- }
-
- System.out.println(color("\n.o0×X×0o. All actions completed. Goodbye. .o0×X×0o.", GREEN));
- }
+ private boolean dryRun;
- static boolean isDryRun() {
+ boolean isDryRun() {
return dryRun;
}
- static void setDryRun(boolean dryRun) {
- PostInstallUpdater.dryRun = dryRun;
+ void setDryRun(boolean dryRun) {
+ this.dryRun = dryRun;
}
- static ProcessBuilder createProcessBuilder(String[] cmd) {
+ ProcessBuilder createProcessBuilder(String[] cmd) {
return new ProcessBuilder(cmd);
}
- static int runCommand(String[] command) {
+ int runCommand(List baseCmd, List args) {
+ String[] command = concat(baseCmd.stream(), args.stream()).toArray(String[]::new);
System.out.println("Executing shell command: " + color(String.join(" ", command), BLUE));
if (isDryRun()) {
System.out.println(color("Dry-run: command not executed.", YELLOW));
diff --git a/src/main/resources/dnf-remove.cf b/src/main/resources/dnf-remove.cf
index d1f8c26..6d86291 100644
--- a/src/main/resources/dnf-remove.cf
+++ b/src/main/resources/dnf-remove.cf
@@ -13,6 +13,7 @@ krdc
krfb
ktnef
neochat
+plasma-discover
plasma-welcome
skanpage
spectacle
diff --git a/src/test/java/cf/maybelambda/fedora/MainTests.java b/src/test/java/cf/maybelambda/fedora/MainTests.java
new file mode 100644
index 0000000..08e7f18
--- /dev/null
+++ b/src/test/java/cf/maybelambda/fedora/MainTests.java
@@ -0,0 +1,121 @@
+package cf.maybelambda.fedora;
+
+import static cf.maybelambda.fedora.ConfigManager.getAdminGroups;
+import static cf.maybelambda.fedora.ConfigManager.getDnfInstallPackages;
+import static cf.maybelambda.fedora.ConfigManager.getDnfRemovePackages;
+import static cf.maybelambda.fedora.ConfigManager.getFlatpakInstallPackages;
+import static cf.maybelambda.fedora.ConfigManager.getFlatpakRemoteName;
+import static cf.maybelambda.fedora.ConfigManager.getFlatpakRemoteUrl;
+import static cf.maybelambda.fedora.ConfigManager.getRPMFusionGpgKeys;
+import static cf.maybelambda.fedora.ConfigManager.getRPMFusionRepos;
+import static cf.maybelambda.fedora.Main.CMD_ADD_USER_TO_GROUP;
+import static cf.maybelambda.fedora.Main.CMD_DNF_AUTORM;
+import static cf.maybelambda.fedora.Main.CMD_DNF_INST;
+import static cf.maybelambda.fedora.Main.CMD_DNF_INST_REPOS;
+import static cf.maybelambda.fedora.Main.CMD_DNF_MARK;
+import static cf.maybelambda.fedora.Main.CMD_DNF_RM;
+import static cf.maybelambda.fedora.Main.CMD_FLATPAK_INST;
+import static cf.maybelambda.fedora.Main.CMD_FLATPAK_REMOTE_ADD;
+import static cf.maybelambda.fedora.Main.CMD_GETENT;
+import static cf.maybelambda.fedora.Main.CMD_RPM_IMPORT;
+import static cf.maybelambda.fedora.Main.CMD_SYSTEMCTL_ENABLE;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+class MainTests {
+ private PostInstallUpdater mockUpdater = mock(PostInstallUpdater.class);
+
+ private void setupConfigManager(MockedStatic cfg) {
+ cfg.when(ConfigManager::getDnfInstallPackages).thenReturn(List.of("pkg1"));
+ cfg.when(ConfigManager::getDnfRemovePackages).thenReturn(List.of("pkg2"));
+ cfg.when(ConfigManager::getFlatpakInstallPackages).thenReturn(List.of("flatpak1"));
+ cfg.when(ConfigManager::getRPMFusionGpgKeys).thenReturn(List.of("key1"));
+ cfg.when(ConfigManager::getRPMFusionRepos).thenReturn(List.of("repo1"));
+ cfg.when(ConfigManager::getFlatpakRemoteName).thenReturn("flathub");
+ cfg.when(ConfigManager::getFlatpakRemoteUrl).thenReturn("https://flathub");
+ cfg.when(ConfigManager::getAdminGroups).thenReturn(List.of("wheel"));
+ }
+
+ private void simulateUserInput() {
+ // Simulate user input: answers to 9 prompts (y/y/empty/y/empty/y/empty/y/y)
+ String input = String.join("\n", "y", "y", "", "y", "", "y", "", "y", "y") + "\n";
+ System.setIn(new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8)));
+ }
+
+ @Test
+ void runExecutesCommandStructureAndSequenceInCorrectOrdering() {
+ try (MockedStatic cfg = mockStatic(ConfigManager.class)) {
+ setupConfigManager(cfg);
+ simulateUserInput();
+ when(mockUpdater.runCommand(any(List.class), any(List.class))).thenReturn(0);
+
+ Main.run(new String[]{}, mockUpdater);
+
+ ArgumentCaptor> captorPrefix = ArgumentCaptor.forClass(List.class);
+ ArgumentCaptor> captorArgs = ArgumentCaptor.forClass(List.class);
+ Mockito.verify(mockUpdater, Mockito.atLeastOnce()).runCommand(captorPrefix.capture(), captorArgs.capture());
+ List> prefixes = captorPrefix.getAllValues();
+ List> args = captorArgs.getAllValues();
+ int i = 0;
+
+ assertEquals(CMD_RPM_IMPORT, prefixes.get(i));
+ assertEquals(getRPMFusionGpgKeys(), args.get(i));
+ i++;
+ assertEquals(CMD_DNF_INST_REPOS, prefixes.get(i));
+ assertEquals(getRPMFusionRepos(), args.get(i));
+ i++;
+ assertEquals(CMD_DNF_INST, prefixes.get(i));
+ assertEquals(getDnfInstallPackages(), args.get(i));
+ i++;
+ assertEquals(CMD_DNF_RM, prefixes.get(i));
+ assertEquals(getDnfRemovePackages(), args.get(i));
+ i++;
+ assertEquals(CMD_DNF_MARK, prefixes.get(i));
+ assertTrue(args.get(i).isEmpty());
+ i++;
+ assertEquals(CMD_DNF_AUTORM, prefixes.get(i));
+ assertTrue(args.get(i).isEmpty());
+ i++;
+ assertEquals(CMD_FLATPAK_REMOTE_ADD, prefixes.get(i));
+ assertEquals(List.of(getFlatpakRemoteName(), getFlatpakRemoteUrl()), args.get(i));
+ i++;
+ assertEquals(CMD_FLATPAK_INST, prefixes.get(i));
+ assertEquals(List.of(getFlatpakRemoteName(), getFlatpakInstallPackages().getFirst()), args.get(i));
+ i++;
+ assertEquals(CMD_GETENT, prefixes.get(i));
+ assertEquals(getAdminGroups(), args.get(i));
+ i++;
+ assertEquals(CMD_ADD_USER_TO_GROUP, prefixes.get(i));
+ assertTrue(args.get(i).containsAll(getAdminGroups()));
+ i++;
+ assertEquals(CMD_SYSTEMCTL_ENABLE, prefixes.get(i));
+ assertTrue(args.get(i).isEmpty());
+ }
+ }
+
+ @Test
+ void helpOptionDisplaysHelpTextAndExits() {
+ try (var filesMock = mockStatic(ConfigManager.class)) {
+ filesMock.when(() -> ConfigManager.readResourceLines(any(String.class)))
+ .thenReturn(List.of("Usage instructions go here"));
+
+ Main.main(new String[]{"--help"});
+ Main.main(new String[]{"-h"});
+
+ filesMock.verify(() -> ConfigManager.getHelpText(), Mockito.times(2));
+ }
+ }
+}
diff --git a/src/test/java/cf/maybelambda/fedora/PostInstallUpdaterTests.java b/src/test/java/cf/maybelambda/fedora/PostInstallUpdaterTests.java
index cd5a8e7..c5db766 100644
--- a/src/test/java/cf/maybelambda/fedora/PostInstallUpdaterTests.java
+++ b/src/test/java/cf/maybelambda/fedora/PostInstallUpdaterTests.java
@@ -1,82 +1,61 @@
package cf.maybelambda.fedora;
-import org.junit.jupiter.api.Test;
-import org.mockito.MockedStatic;
-import org.mockito.Mockito;
+import static java.util.Arrays.asList;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
-import java.util.List;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.Mockito.CALLS_REAL_METHODS;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.mockStatic;
-import static org.mockito.Mockito.when;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
class PostInstallUpdaterTests {
+ private PostInstallUpdater updater;
+ private ProcessBuilder mockBuilder;
+
+ @BeforeEach
+ void setUp() {
+ this.updater = Mockito.spy(new PostInstallUpdater());
+ this.mockBuilder = mock(ProcessBuilder.class);
+ }
+
@Test
void runCommandReturnsStatusCodeOfCommandExecuted() throws Exception {
Process mockProcess = mock(Process.class);
when(mockProcess.getInputStream()).thenReturn(new ByteArrayInputStream("ok".getBytes(StandardCharsets.UTF_8)));
when(mockProcess.waitFor()).thenReturn(0);
-
- ProcessBuilder mockBuilder = mock(ProcessBuilder.class);
when(mockBuilder.start()).thenReturn(mockProcess);
when(mockBuilder.redirectErrorStream(true)).thenReturn(mockBuilder);
+ Mockito.doReturn(mockBuilder).when(updater).createProcessBuilder(any(String[].class));
- try (MockedStatic updaterMock = Mockito.mockStatic(PostInstallUpdater.class, CALLS_REAL_METHODS)) {
- updaterMock.when(() -> PostInstallUpdater.createProcessBuilder(any(String[].class)))
- .thenReturn(mockBuilder);
+ int exitCode = updater.runCommand(asList("echo"), asList("test"));
- int exitCode = PostInstallUpdater.runCommand(new String[]{"echo", "test"});
-
- assertEquals(0, exitCode);
- }
+ assertEquals(0, exitCode);
}
@Test
void runCommandReturnsStatusMinusOneOnIOException() throws Exception {
- ProcessBuilder mockBuilder = mock(ProcessBuilder.class);
when(mockBuilder.start()).thenThrow(new IOException("Simulated I/O error"));
+ Mockito.doReturn(mockBuilder).when(updater).createProcessBuilder(any(String[].class));
- try (MockedStatic updaterMock = Mockito.mockStatic(PostInstallUpdater.class, CALLS_REAL_METHODS)) {
- updaterMock.when(() -> PostInstallUpdater.createProcessBuilder(any(String[].class)))
- .thenReturn(mockBuilder);
-
- int exitCode = PostInstallUpdater.runCommand(new String[]{"failing", "cmd"});
+ int exitCode = updater.runCommand(asList("failing"), asList("cmd"));
- assertEquals(-1, exitCode);
- }
+ assertEquals(-1, exitCode);
}
@Test
void runCommandSkipsExecutionInDryRunMode() {
- PostInstallUpdater.setDryRun(true);
- try (MockedStatic updaterMock = Mockito.mockStatic(PostInstallUpdater.class, CALLS_REAL_METHODS)) {
- updaterMock.when(() -> PostInstallUpdater.createProcessBuilder(any(String[].class)))
- .thenThrow(new AssertionError("Should not create ProcessBuilder in dry-run mode"));
-
- int exitCode = PostInstallUpdater.runCommand(new String[]{"fake", "cmd"});
-
- assertEquals(0, exitCode);
- } finally {
- PostInstallUpdater.setDryRun(false);
- }
- }
-
- @Test
- void helpOptionDisplaysHelpTextAndExits() {
- try (MockedStatic filesMock = mockStatic(ConfigManager.class)) {
- filesMock.when(() -> ConfigManager.readResourceLines(any(String.class)))
- .thenReturn(List.of("Usage instructions go here"));
+ updater.setDryRun(true);
+ Mockito.doThrow(new AssertionError("Should not create ProcessBuilder in dry-run mode"))
+ .when(updater).createProcessBuilder(any(String[].class));
- PostInstallUpdater.main(new String[]{"--help"});
- PostInstallUpdater.main(new String[]{"-h"});
+ int exitCode = updater.runCommand(asList("fake"), asList("cmd"));
- filesMock.verify(() -> ConfigManager.getHelpText(), Mockito.times(2));
- }
+ assertEquals(0, exitCode);
}
}