diff --git a/core/src/main/java/hudson/cli/DeleteNodeCommand.java b/core/src/main/java/hudson/cli/DeleteNodeCommand.java new file mode 100644 index 000000000000..a0af322a99a4 --- /dev/null +++ b/core/src/main/java/hudson/cli/DeleteNodeCommand.java @@ -0,0 +1,90 @@ +/* + * The MIT License + * + * Copyright (c) 2015 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package hudson.cli; + +import hudson.Extension; +import hudson.model.Computer; +import hudson.model.Node; +import jenkins.model.Jenkins; +import org.kohsuke.args4j.Argument; + +import java.util.HashSet; +import java.util.List; + +/** + * @author pjanouse + * @since TODO + */ +@Extension +public class DeleteNodeCommand extends CLICommand { + + @Argument(usage="Nodes name to delete", required=true, multiValued=true) + private List nodes; + + @Override + public String getShortDescription() { + + return Messages.DeleteNodeCommand_ShortDescription(); + } + + @Override + protected int run() throws Exception { + + boolean errorOccurred = false; + + HashSet hs = new HashSet(); + hs.addAll(nodes); + + for (String node_s : hs) { + + Node node = Jenkins.getInstance().getNode(node_s); + + if(node == null) { + stderr.format("No such node '%s'\n", node_s); + errorOccurred = true; + continue; + } + + try { + node.checkPermission(Computer.DELETE); + } catch (Exception e) { + stderr.println(e.getMessage()); + errorOccurred = true; + continue; + } + + try { + Jenkins.getInstance().removeNode(node); + } catch (Exception e) { + stderr.format("Unexpected exception occurred during deletion of node '%s': %s\n", + node.getDisplayName(), + e.getMessage() + ); + errorOccurred = true; + continue; + } + } + return errorOccurred ? -1 : 0; + } +} diff --git a/core/src/main/java/hudson/model/Computer.java b/core/src/main/java/hudson/model/Computer.java index a9e802ff985d..022de2163599 100644 --- a/core/src/main/java/hudson/model/Computer.java +++ b/core/src/main/java/hudson/model/Computer.java @@ -1292,7 +1292,7 @@ public void updateByXml(final InputStream source) throws IOException, ServletExc /** * Really deletes the slave. */ - @CLIMethod(name="delete-node") +// @CLIMethod(name="delete-node") @RequirePOST public HttpResponse doDoDelete() throws IOException { checkPermission(DELETE); diff --git a/core/src/main/resources/hudson/cli/Messages.properties b/core/src/main/resources/hudson/cli/Messages.properties index a19903a24c29..2713ac15a68f 100644 --- a/core/src/main/resources/hudson/cli/Messages.properties +++ b/core/src/main/resources/hudson/cli/Messages.properties @@ -78,3 +78,7 @@ BuildCommand.CLICause.CannotBuildConfigNotSaved=\ Cannot build {0} because its configuration has not been saved. BuildCommand.CLICause.CannotBuildUnknownReasons=\ Cannot build {0} for unknown reasons. + +DeleteNodeCommand.ShortDescription=\ + Deletes node(s) + diff --git a/core/src/main/resources/hudson/cli/Messages_da.properties b/core/src/main/resources/hudson/cli/Messages_da.properties new file mode 100644 index 000000000000..05f432a523d2 --- /dev/null +++ b/core/src/main/resources/hudson/cli/Messages_da.properties @@ -0,0 +1 @@ +DeleteNodeCommand.ShortDescription=Sletter en node diff --git a/core/src/main/resources/hudson/cli/Messages_de.properties b/core/src/main/resources/hudson/cli/Messages_de.properties new file mode 100644 index 000000000000..3e0b58947821 --- /dev/null +++ b/core/src/main/resources/hudson/cli/Messages_de.properties @@ -0,0 +1 @@ +DeleteNodeCommand.ShortDescription=Knoten l\u00f6schen. diff --git a/core/src/main/resources/hudson/cli/Messages_es.properties b/core/src/main/resources/hudson/cli/Messages_es.properties index 9f56ca37c034..12bf0a59e3e1 100644 --- a/core/src/main/resources/hudson/cli/Messages_es.properties +++ b/core/src/main/resources/hudson/cli/Messages_es.properties @@ -48,3 +48,4 @@ UpdateJobCommand.ShortDescription=Actualiza el fichero XML de la definici GroovyshCommand.ShortDescription=Ejecuta una shell interactiva de groovy. SetBuildDescriptionCommand.ShortDescription=Establece la descripción de una ejecución. +DeleteNodeCommand.ShortDescription=Borrar un nodo diff --git a/core/src/main/resources/hudson/cli/Messages_it.properties b/core/src/main/resources/hudson/cli/Messages_it.properties new file mode 100644 index 000000000000..fd75db7ef48d --- /dev/null +++ b/core/src/main/resources/hudson/cli/Messages_it.properties @@ -0,0 +1 @@ +DeleteNodeCommand.ShortDescription=Cancella un nodo diff --git a/core/src/main/resources/hudson/cli/Messages_ja.properties b/core/src/main/resources/hudson/cli/Messages_ja.properties index 9399b7f78b73..f13882e426f2 100644 --- a/core/src/main/resources/hudson/cli/Messages_ja.properties +++ b/core/src/main/resources/hudson/cli/Messages_ja.properties @@ -68,4 +68,6 @@ BuildCommand.CLICause.CannotBuildDisabled=\ BuildCommand.CLICause.CannotBuildConfigNotSaved=\ \u8a2d\u5b9a\u304c\u4fdd\u5b58\u3055\u308c\u3066\u3044\u306a\u3044\u306e\u3067{0}\u3092\u30d3\u30eb\u30c9\u3067\u304d\u307e\u305b\u3093\u3002 BuildCommand.CLICause.CannotBuildUnknownReasons=\ - \u30d3\u30eb\u30c9\u3067\u304d\u307e\u305b\u3093(\u539f\u56e0\u4e0d\u660e)\u3002 \ No newline at end of file + \u30d3\u30eb\u30c9\u3067\u304d\u307e\u305b\u3093(\u539f\u56e0\u4e0d\u660e)\u3002 + +DeleteNodeCommand.ShortDescription=\u30ce\u30fc\u30c9\u3092\u524a\u9664\u3057\u307e\u3059\u3002 diff --git a/core/src/main/resources/hudson/cli/Messages_pt_BR.properties b/core/src/main/resources/hudson/cli/Messages_pt_BR.properties index 007038f34b82..f120c3602250 100644 --- a/core/src/main/resources/hudson/cli/Messages_pt_BR.properties +++ b/core/src/main/resources/hudson/cli/Messages_pt_BR.properties @@ -110,3 +110,6 @@ SessionIdCommand.ShortDescription=Exibe o ID de sess\u00e3o, que muda toda vez q InstallPluginCommand.InstallingPluginFromUrl=Instalando um plugin de {0} # Installs a plugin either from a file, an URL, or from update center. InstallPluginCommand.ShortDescription=Instala um plugin a partir de um arquivo, uma URL, ou da central de atualiza\u00e7\u00f5es. + +# Deletes a node +CLI.delete-node.shortDescription=Remover o n\u00f3 diff --git a/core/src/main/resources/hudson/cli/Messages_zh_CN.properties b/core/src/main/resources/hudson/cli/Messages_zh_CN.properties new file mode 100644 index 000000000000..8011124de842 --- /dev/null +++ b/core/src/main/resources/hudson/cli/Messages_zh_CN.properties @@ -0,0 +1 @@ +DeleteNodeCommand.ShortDescription=Deletes a node diff --git a/core/src/main/resources/hudson/cli/Messages_zh_TW.properties b/core/src/main/resources/hudson/cli/Messages_zh_TW.properties index 0cf6f8ec1827..5953f6537c2f 100644 --- a/core/src/main/resources/hudson/cli/Messages_zh_TW.properties +++ b/core/src/main/resources/hudson/cli/Messages_zh_TW.properties @@ -72,3 +72,5 @@ WhoAmICommand.ShortDescription=\ UpdateJobCommand.ShortDescription=\ \u7531 stdin \u66f4\u65b0\u4f5c\u696d\u5b9a\u7fa9 XML\u3002get-job \u6307\u4ee4\u7684\u76f8\u53cd BuildCommand.CLICause.ShortDescription=\u7531 {0} \u7684\u547d\u4ee4\u5217\u4ecb\u9762\u555f\u52d5 + +DeleteNodeCommand.ShortDescription=\u522a\u9664\u6307\u5b9a\u7bc0\u9ede\u3002 diff --git a/core/src/main/resources/hudson/model/Messages.properties b/core/src/main/resources/hudson/model/Messages.properties index 7c3cab01b29c..110409b09b17 100644 --- a/core/src/main/resources/hudson/model/Messages.properties +++ b/core/src/main/resources/hudson/model/Messages.properties @@ -97,7 +97,6 @@ CLI.delete-job.shortDescription=Deletes a job. CLI.reload-job.shortDescription=Reloads this job from disk. CLI.disable-job.shortDescription=Disables a job. CLI.enable-job.shortDescription=Enables a job. -CLI.delete-node.shortDescription=Deletes a node. CLI.disconnect-node.shortDescription=Disconnects from a node. CLI.connect-node.shortDescription=Reconnect to a node. CLI.online-node.shortDescription=Resume using a node for performing builds, to cancel out the earlier "offline-node" command. diff --git a/core/src/main/resources/hudson/model/Messages_da.properties b/core/src/main/resources/hudson/model/Messages_da.properties index f17335347aff..b5b4c9ed7a84 100644 --- a/core/src/main/resources/hudson/model/Messages_da.properties +++ b/core/src/main/resources/hudson/model/Messages_da.properties @@ -144,7 +144,6 @@ UpdateCenter.PluginCategory.scm=Kildekodestyring (SCM) View.ConfigurePermission.Description=Denne rettighed tillader brugere at \u00e6ndre konfigurationen af visninger. AbstractProject.NewBuildForWorkspace=Skedulerer et nyt byg for at f\u00e5 et arbejdsomr\u00e5de Node.LabelMissing={0} har ikke etiket {1} -CLI.delete-node.shortDescription=Sletter en node Queue.BlockedBy=Blokeret af {0} Node.BecauseNodeIsReserved={0} er reserveret til jobs bundet(tied) til den Job.minutes=min diff --git a/core/src/main/resources/hudson/model/Messages_de.properties b/core/src/main/resources/hudson/model/Messages_de.properties index 90cc3429225b..8da9942ec767 100644 --- a/core/src/main/resources/hudson/model/Messages_de.properties +++ b/core/src/main/resources/hudson/model/Messages_de.properties @@ -88,7 +88,6 @@ CLI.disable-job.shortDescription=Job deaktivieren. CLI.enable-job.shortDescription=Job aktivieren. CLI.connect-node.shortDescription=Erneut mit Knoten verbinden. CLI.disconnect-node.shortDescription=Knoten trennen. -CLI.delete-node.shortDescription=Knoten l\u00f6schen. CLI.offline-node.shortDescription=Knoten wird bis zum n\u00e4chsten "online-node"-Kommando f\u00fcr keine neuen Builds verwendet. CLI.online-node.shortDescription=Knoten wird wieder f\u00fcr neue Builds verwendet. Hebt ein vorausgegangenes "offline-node"-Kommando auf. CLI.safe-restart.shortDescription=Startet Jenkins neu. diff --git a/core/src/main/resources/hudson/model/Messages_es.properties b/core/src/main/resources/hudson/model/Messages_es.properties index 02b9081a433a..2e20c2495d2a 100644 --- a/core/src/main/resources/hudson/model/Messages_es.properties +++ b/core/src/main/resources/hudson/model/Messages_es.properties @@ -62,7 +62,6 @@ CLI.clear-queue.shortDescription=Limpiar la cola de trabajos CLI.delete-job.shortDescription=Borrar una tarea CLI.disable-job.shortDescription=Desactivar una tarea CLI.enable-job.shortDescription=Activar una tarea -CLI.delete-node.shortDescription=Borrar un nodo CLI.disconnect-node.shortDescription=Desconectarse de un nodo CLI.connect-node.shortDescription=Reconectarse con un nodo CLI.online-node.shortDescription=Continuar usando un nodo y candelar el comando "offline-node" mas reciente. diff --git a/core/src/main/resources/hudson/model/Messages_it.properties b/core/src/main/resources/hudson/model/Messages_it.properties index e8b51dcaa4ec..905f2beaa6c3 100644 --- a/core/src/main/resources/hudson/model/Messages_it.properties +++ b/core/src/main/resources/hudson/model/Messages_it.properties @@ -80,7 +80,6 @@ CLI.clear-queue.shortDescription=Pulisce la coda di lavoro CLI.delete-job.shortDescription=Cancella un job CLI.disable-job.shortDescription=Disabilita un job CLI.enable-job.shortDescription=Abilita un job -CLI.delete-node.shortDescription=Cancella un nodo CLI.disconnect-node.shortDescription=Disconnects from a node CLI.connect-node.shortDescription=Riconnettersi ad un nodo CLI.online-node.shortDescription=Resume using a node for performing builds, to cancel out the earlier "offline-node" command. diff --git a/core/src/main/resources/hudson/model/Messages_ja.properties b/core/src/main/resources/hudson/model/Messages_ja.properties index f47d7cb6859b..088506a5b88b 100644 --- a/core/src/main/resources/hudson/model/Messages_ja.properties +++ b/core/src/main/resources/hudson/model/Messages_ja.properties @@ -323,7 +323,6 @@ CLI.clear-queue.shortDescription=\u30d3\u30eb\u30c9\u30ad\u30e5\u30fc\u3092\u30a CLI.delete-job.shortDescription=\u30b8\u30e7\u30d6\u3092\u524a\u9664\u3057\u307e\u3059\u3002 CLI.disable-job.shortDescription=\u30b8\u30e7\u30d6\u3092\u7121\u52b9\u5316\u3057\u307e\u3059\u3002 CLI.enable-job.shortDescription=\u30b8\u30e7\u30d6\u3092\u6709\u52b9\u5316\u3057\u307e\u3059\u3002 -CLI.delete-node.shortDescription=\u30ce\u30fc\u30c9\u3092\u524a\u9664\u3057\u307e\u3059\u3002 CLI.disconnect-node.shortDescription=\u30ce\u30fc\u30c9\u3068\u306e\u63a5\u7d9a\u3092\u5207\u65ad\u3057\u307e\u3059\u3002 CLI.connect-node.shortDescription=\u30ce\u30fc\u30c9\u3068\u518d\u63a5\u7d9a\u3057\u307e\u3059\u3002 CLI.online-node.shortDescription=\u76f4\u524d\u306b\u5b9f\u884c\u3057\u305f"online-node"\u30b3\u30de\u30f3\u30c9\u3092\u53d6\u308a\u6d88\u3057\u3001\u30d3\u30eb\u30c9\u3092\u5b9f\u884c\u3059\u308b\u30ce\u30fc\u30c9\u306e\u4f7f\u7528\u3092\u518d\u958b\u3057\u307e\u3059\u3002 diff --git a/core/src/main/resources/hudson/model/Messages_pt_BR.properties b/core/src/main/resources/hudson/model/Messages_pt_BR.properties index a095bef6dd06..770d0ab6d2cd 100644 --- a/core/src/main/resources/hudson/model/Messages_pt_BR.properties +++ b/core/src/main/resources/hudson/model/Messages_pt_BR.properties @@ -278,8 +278,6 @@ View.ConfigurePermission.Description=Permite aos usu\u00e1rios configurar as vie AbstractProject.NewBuildForWorkspace=Agendando uma novo build para obter um novo workspace # {0} doesn''t have label {1} Node.LabelMissing=R\u00f3tulo n\u00e3o encontrado -# Deletes a node -CLI.delete-node.shortDescription=Remover o n\u00f3 # {0} is reserved for jobs tied to it Node.BecauseNodeIsReserved={0} foi reservado para trabalhos vinculados # Started by remote host {0} with note: {1} diff --git a/core/src/main/resources/hudson/model/Messages_zh_CN.properties b/core/src/main/resources/hudson/model/Messages_zh_CN.properties index 68850858d4c5..72dc15f49223 100644 --- a/core/src/main/resources/hudson/model/Messages_zh_CN.properties +++ b/core/src/main/resources/hudson/model/Messages_zh_CN.properties @@ -66,7 +66,6 @@ CLI.clear-queue.shortDescription=Clears the build queue CLI.delete-job.shortDescription=Deletes a job CLI.disable-job.shortDescription=Disables a job CLI.enable-job.shortDescription=Enables a job -CLI.delete-node.shortDescription=Deletes a node CLI.disconnect-node.shortDescription=Disconnects from a node CLI.connect-node.shortDescription=Reconnect to a node CLI.online-node.shortDescription=Resume using a node for performing builds, to cancel out the earlier "offline-node" command. diff --git a/core/src/main/resources/hudson/model/Messages_zh_TW.properties b/core/src/main/resources/hudson/model/Messages_zh_TW.properties index b6fd160a90b7..6866a8163e39 100644 --- a/core/src/main/resources/hudson/model/Messages_zh_TW.properties +++ b/core/src/main/resources/hudson/model/Messages_zh_TW.properties @@ -85,7 +85,6 @@ CLI.clear-queue.shortDescription=\u6e05\u9664\u5efa\u7f6e\u4f47\u5217\u3002 CLI.delete-job.shortDescription=\u522a\u9664\u4f5c\u696d\u3002 CLI.disable-job.shortDescription=\u505c\u7528\u4f5c\u696d\u3002 CLI.enable-job.shortDescription=\u555f\u7528\u4f5c\u696d\u3002 -CLI.delete-node.shortDescription=\u522a\u9664\u6307\u5b9a\u7bc0\u9ede\u3002 CLI.disconnect-node.shortDescription=\u4e2d\u65b7\u8207\u6307\u5b9a\u7bc0\u9ede\u7684\u9023\u7dda\u3002 CLI.connect-node.shortDescription=\u9023\u7dda\u5230\u6307\u5b9a\u7bc0\u9ede\u3002 CLI.online-node.shortDescription=\u7e7c\u7e8c\u4f7f\u7528\u6307\u5b9a\u7bc0\u9ede\u4f86\u5efa\u7f6e\uff0c\u53d6\u6d88\u5148\u524d\u7684 "offline-node" \u6307\u4ee4\u3002 diff --git a/test/src/test/java/hudson/cli/DeleteNodeCommandTest.java b/test/src/test/java/hudson/cli/DeleteNodeCommandTest.java new file mode 100644 index 000000000000..d0d3b5fa8f06 --- /dev/null +++ b/test/src/test/java/hudson/cli/DeleteNodeCommandTest.java @@ -0,0 +1,147 @@ +/* + * The MIT License + * + * Copyright 2015 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/** + * @author pjanouse + * @since TODO + */ + +package hudson.cli; + +import hudson.model.Computer; +import hudson.slaves.DumbSlave; +import hudson.slaves.NodeProperty; +import jenkins.model.Jenkins; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; + +import java.util.ArrayList; + +import static hudson.cli.CLICommandInvoker.Matcher.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.notNullValue; + +public class DeleteNodeCommandTest { + + private CLICommandInvoker command; + + @Rule public final JenkinsRule j = new JenkinsRule(); + + @Before public void setUp() { + + command = new CLICommandInvoker(j, new DeleteNodeCommand()); + } + + @Test public void deleteNodeShouldFailWithoutNodeDeletePermission() throws Exception { + + j.createSlave("aNode", "", null); + + final CLICommandInvoker.Result result = command + .authorizedTo(Jenkins.READ) + .invokeWithArgs("aNode") + ; + + assertThat(result, failedWith(-1)); + assertThat(result, hasNoStandardOutput()); + assertThat(result.stderr(), containsString("user is missing the Slave/Delete permission")); + } + + @Test public void deleteNodeShouldSucceed() throws Exception { + + j.createSlave("aNode", "", null); + + final CLICommandInvoker.Result result = command + .authorizedTo(Computer.DELETE, Jenkins.READ) + .invokeWithArgs("aNode") + ; + + assertThat(result, succeededSilently()); + assertThat(j.jenkins.getNode("aNode"), nullValue()); + } + + @Test public void deleteNodeShouldFailIfNodeDoesNotExist() { + + final CLICommandInvoker.Result result = command + .authorizedTo(Computer.DELETE, Jenkins.READ) + .invokeWithArgs("never_created") + ; + + assertThat(result, failedWith(-1)); + assertThat(result, hasNoStandardOutput()); + assertThat(result.stderr(), containsString("No such node 'never_created'")); + } + + @Test public void deleteNodeManyShouldSucceed() throws Exception { + + j.createSlave("aNode1", "", null); + j.createSlave("aNode2", "", null); + j.createSlave("aNode3", "", null); + + final CLICommandInvoker.Result result = command + .authorizedTo(Computer.DELETE, Jenkins.READ) + .invokeWithArgs("aNode1", "aNode2", "aNode3"); + + assertThat(result, succeededSilently()); + assertThat(j.jenkins.getView("aNode1"), nullValue()); + assertThat(j.jenkins.getView("aNode2"), nullValue()); + assertThat(j.jenkins.getView("aNode3"), nullValue()); + } + + @Test public void deleteNodeManyShouldFailIfANodeDoesNotExist() throws Exception { + + j.createSlave("aNode1", "", null); + j.createSlave("aNode2", "", null); + + final CLICommandInvoker.Result result = command + .authorizedTo(Computer.DELETE, Jenkins.READ) + .invokeWithArgs("aNode1", "aNode2", "never_created"); + + assertThat(result, failedWith(-1)); + assertThat(result, hasNoStandardOutput()); + assertThat(result.stderr(), containsString("No such node 'never_created'")); + + assertThat(j.jenkins.getView("aNode1"), nullValue()); + assertThat(j.jenkins.getView("aNode2"), nullValue()); + assertThat(j.jenkins.getView("never_created"), nullValue()); + } + + @Test public void deleteNodeManyShouldSucceedEvenANodeIsSpecifiedTwice() throws Exception { + + j.createSlave("aNode1", "", null); + j.createSlave("aNode2", "", null); + + final CLICommandInvoker.Result result = command + .authorizedTo(Computer.DELETE, Jenkins.READ) + .invokeWithArgs("aNode1", "aNode2", "aNode1"); + + assertThat(result, succeededSilently()); + assertThat(j.jenkins.getView("aNode1"), nullValue()); + assertThat(j.jenkins.getView("aNode2"), nullValue()); + } +}