1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 package org.apache.hadoop.yarn.client.cli;
20 
21 import static org.junit.Assert.*;
22 import static org.mockito.Matchers.any;
23 import static org.mockito.Matchers.anyInt;
24 import static org.mockito.Matchers.argThat;
25 import static org.mockito.Matchers.eq;
26 import static org.mockito.Mockito.mock;
27 import static org.mockito.Mockito.never;
28 import static org.mockito.Mockito.verify;
29 import static org.mockito.Mockito.when;
30 
31 import java.io.ByteArrayOutputStream;
32 import java.io.IOException;
33 import java.io.PrintStream;
34 
35 import org.apache.hadoop.conf.Configuration;
36 import org.apache.hadoop.ha.HAServiceProtocol;
37 import org.apache.hadoop.ha.HAServiceStatus;
38 import org.apache.hadoop.ha.HAServiceTarget;
39 import org.apache.hadoop.service.Service.STATE;
40 import org.apache.hadoop.yarn.api.records.NodeId;
41 import org.apache.hadoop.yarn.client.cli.RMAdminCLI;
42 import org.apache.hadoop.yarn.conf.YarnConfiguration;
43 import org.apache.hadoop.yarn.exceptions.YarnException;
44 import org.apache.hadoop.yarn.nodelabels.CommonNodeLabelsManager;
45 import org.apache.hadoop.yarn.nodelabels.DummyCommonNodeLabelsManager;
46 import org.apache.hadoop.yarn.server.api.ResourceManagerAdministrationProtocol;
47 import org.apache.hadoop.yarn.server.api.protocolrecords.AddToClusterNodeLabelsRequest;
48 import org.apache.hadoop.yarn.server.api.protocolrecords.AddToClusterNodeLabelsResponse;
49 import org.apache.hadoop.yarn.server.api.protocolrecords.RefreshAdminAclsRequest;
50 import org.apache.hadoop.yarn.server.api.protocolrecords.RefreshNodesRequest;
51 import org.apache.hadoop.yarn.server.api.protocolrecords.RefreshQueuesRequest;
52 import org.apache.hadoop.yarn.server.api.protocolrecords.RefreshServiceAclsRequest;
53 import org.apache.hadoop.yarn.server.api.protocolrecords.RefreshSuperUserGroupsConfigurationRequest;
54 import org.apache.hadoop.yarn.server.api.protocolrecords.RefreshUserToGroupsMappingsRequest;
55 import org.junit.Before;
56 import org.junit.Test;
57 import org.mockito.ArgumentMatcher;
58 import org.mockito.invocation.InvocationOnMock;
59 import org.mockito.stubbing.Answer;
60 
61 import com.google.common.base.Charsets;
62 import com.google.common.collect.ImmutableSet;
63 
64 public class TestRMAdminCLI {
65 
66   private ResourceManagerAdministrationProtocol admin;
67   private HAServiceProtocol haadmin;
68   private RMAdminCLI rmAdminCLI;
69   private RMAdminCLI rmAdminCLIWithHAEnabled;
70   private CommonNodeLabelsManager dummyNodeLabelsManager;
71   private boolean remoteAdminServiceAccessed = false;
72 
73   @SuppressWarnings("static-access")
74   @Before
configure()75   public void configure() throws IOException, YarnException {
76     remoteAdminServiceAccessed = false;
77     admin = mock(ResourceManagerAdministrationProtocol.class);
78     when(admin.addToClusterNodeLabels(any(AddToClusterNodeLabelsRequest.class)))
79         .thenAnswer(new Answer<AddToClusterNodeLabelsResponse>() {
80 
81           @Override
82           public AddToClusterNodeLabelsResponse answer(
83               InvocationOnMock invocation) throws Throwable {
84             remoteAdminServiceAccessed = true;
85             return AddToClusterNodeLabelsResponse.newInstance();
86           }
87         });
88 
89     haadmin = mock(HAServiceProtocol.class);
90     when(haadmin.getServiceStatus()).thenReturn(new HAServiceStatus(
91         HAServiceProtocol.HAServiceState.INITIALIZING));
92 
93     final HAServiceTarget haServiceTarget = mock(HAServiceTarget.class);
94     when(haServiceTarget.getProxy(any(Configuration.class), anyInt()))
95         .thenReturn(haadmin);
96     rmAdminCLI = new RMAdminCLI(new Configuration()) {
97       @Override
98       protected ResourceManagerAdministrationProtocol createAdminProtocol()
99           throws IOException {
100         return admin;
101       }
102 
103       @Override
104       protected HAServiceTarget resolveTarget(String rmId) {
105         return haServiceTarget;
106       }
107     };
108     initDummyNodeLabelsManager();
109     rmAdminCLI.localNodeLabelsManager = dummyNodeLabelsManager;
110 
111     YarnConfiguration conf = new YarnConfiguration();
112     conf.setBoolean(YarnConfiguration.RM_HA_ENABLED, true);
113     rmAdminCLIWithHAEnabled = new RMAdminCLI(conf) {
114 
115       @Override
116       protected ResourceManagerAdministrationProtocol createAdminProtocol()
117           throws IOException {
118         return admin;
119       }
120 
121       @Override
122       protected HAServiceTarget resolveTarget(String rmId) {
123         return haServiceTarget;
124       }
125     };
126   }
127 
initDummyNodeLabelsManager()128   private void initDummyNodeLabelsManager() {
129     Configuration conf = new YarnConfiguration();
130     conf.setBoolean(YarnConfiguration.NODE_LABELS_ENABLED, true);
131     dummyNodeLabelsManager = new DummyCommonNodeLabelsManager();
132     dummyNodeLabelsManager.init(conf);
133   }
134 
135   @Test(timeout=500)
testRefreshQueues()136   public void testRefreshQueues() throws Exception {
137     String[] args = { "-refreshQueues" };
138     assertEquals(0, rmAdminCLI.run(args));
139     verify(admin).refreshQueues(any(RefreshQueuesRequest.class));
140   }
141 
142   @Test(timeout=500)
testRefreshUserToGroupsMappings()143   public void testRefreshUserToGroupsMappings() throws Exception {
144     String[] args = { "-refreshUserToGroupsMappings" };
145     assertEquals(0, rmAdminCLI.run(args));
146     verify(admin).refreshUserToGroupsMappings(
147         any(RefreshUserToGroupsMappingsRequest.class));
148   }
149 
150   @Test(timeout=500)
testRefreshSuperUserGroupsConfiguration()151   public void testRefreshSuperUserGroupsConfiguration() throws Exception {
152     String[] args = { "-refreshSuperUserGroupsConfiguration" };
153     assertEquals(0, rmAdminCLI.run(args));
154     verify(admin).refreshSuperUserGroupsConfiguration(
155         any(RefreshSuperUserGroupsConfigurationRequest.class));
156   }
157 
158   @Test(timeout=500)
testRefreshAdminAcls()159   public void testRefreshAdminAcls() throws Exception {
160     String[] args = { "-refreshAdminAcls" };
161     assertEquals(0, rmAdminCLI.run(args));
162     verify(admin).refreshAdminAcls(any(RefreshAdminAclsRequest.class));
163   }
164 
165   @Test(timeout=500)
testRefreshServiceAcl()166   public void testRefreshServiceAcl() throws Exception {
167     String[] args = { "-refreshServiceAcl" };
168     assertEquals(0, rmAdminCLI.run(args));
169     verify(admin).refreshServiceAcls(any(RefreshServiceAclsRequest.class));
170   }
171 
172   @Test(timeout=500)
testRefreshNodes()173   public void testRefreshNodes() throws Exception {
174     String[] args = { "-refreshNodes" };
175     assertEquals(0, rmAdminCLI.run(args));
176     verify(admin).refreshNodes(any(RefreshNodesRequest.class));
177   }
178 
179   @Test(timeout=500)
testGetGroups()180   public void testGetGroups() throws Exception {
181     when(admin.getGroupsForUser(eq("admin"))).thenReturn(
182         new String[] {"group1", "group2"});
183     PrintStream origOut = System.out;
184     PrintStream out = mock(PrintStream.class);
185     System.setOut(out);
186     try {
187       String[] args = { "-getGroups", "admin" };
188       assertEquals(0, rmAdminCLI.run(args));
189       verify(admin).getGroupsForUser(eq("admin"));
190       verify(out).println(argThat(new ArgumentMatcher<StringBuilder>() {
191         @Override
192         public boolean matches(Object argument) {
193           return ("" + argument).equals("admin : group1 group2");
194         }
195       }));
196     } finally {
197       System.setOut(origOut);
198     }
199   }
200 
201   @Test(timeout = 500)
testTransitionToActive()202   public void testTransitionToActive() throws Exception {
203     String[] args = {"-transitionToActive", "rm1"};
204 
205     // RM HA is disabled.
206     // transitionToActive should not be executed
207     assertEquals(-1, rmAdminCLI.run(args));
208     verify(haadmin, never()).transitionToActive(
209         any(HAServiceProtocol.StateChangeRequestInfo.class));
210 
211     // Now RM HA is enabled.
212     // transitionToActive should be executed
213     assertEquals(0, rmAdminCLIWithHAEnabled.run(args));
214     verify(haadmin).transitionToActive(
215         any(HAServiceProtocol.StateChangeRequestInfo.class));
216   }
217 
218   @Test(timeout = 500)
testTransitionToStandby()219   public void testTransitionToStandby() throws Exception {
220     String[] args = {"-transitionToStandby", "rm1"};
221 
222     // RM HA is disabled.
223     // transitionToStandby should not be executed
224     assertEquals(-1, rmAdminCLI.run(args));
225     verify(haadmin, never()).transitionToStandby(
226         any(HAServiceProtocol.StateChangeRequestInfo.class));
227 
228     // Now RM HA is enabled.
229     // transitionToActive should be executed
230     assertEquals(0, rmAdminCLIWithHAEnabled.run(args));
231     verify(haadmin).transitionToStandby(
232         any(HAServiceProtocol.StateChangeRequestInfo.class));
233   }
234 
235   @Test(timeout = 500)
testGetServiceState()236   public void testGetServiceState() throws Exception {
237     String[] args = {"-getServiceState", "rm1"};
238 
239     // RM HA is disabled.
240     // getServiceState should not be executed
241     assertEquals(-1, rmAdminCLI.run(args));
242     verify(haadmin, never()).getServiceStatus();
243 
244     // Now RM HA is enabled.
245     // getServiceState should be executed
246     assertEquals(0, rmAdminCLIWithHAEnabled.run(args));
247     verify(haadmin).getServiceStatus();
248   }
249 
250   @Test(timeout = 500)
testCheckHealth()251   public void testCheckHealth() throws Exception {
252     String[] args = {"-checkHealth", "rm1"};
253 
254     // RM HA is disabled.
255     // getServiceState should not be executed
256     assertEquals(-1, rmAdminCLI.run(args));
257     verify(haadmin, never()).monitorHealth();
258 
259     // Now RM HA is enabled.
260     // getServiceState should be executed
261     assertEquals(0, rmAdminCLIWithHAEnabled.run(args));
262     verify(haadmin).monitorHealth();
263   }
264 
265   /**
266    * Test printing of help messages
267    */
268   @Test(timeout=500)
testHelp()269   public void testHelp() throws Exception {
270     PrintStream oldOutPrintStream = System.out;
271     PrintStream oldErrPrintStream = System.err;
272     ByteArrayOutputStream dataOut = new ByteArrayOutputStream();
273     ByteArrayOutputStream dataErr = new ByteArrayOutputStream();
274     System.setOut(new PrintStream(dataOut));
275     System.setErr(new PrintStream(dataErr));
276     try {
277       String[] args = { "-help" };
278       assertEquals(0, rmAdminCLI.run(args));
279       oldOutPrintStream.println(dataOut);
280       assertTrue(dataOut
281           .toString()
282           .contains(
283               "rmadmin is the command to execute YARN administrative commands."));
284       assertTrue(dataOut
285           .toString()
286           .contains(
287               "yarn rmadmin [-refreshQueues] [-refreshNodes] [-refreshSuper" +
288               "UserGroupsConfiguration] [-refreshUserToGroupsMappings] " +
289               "[-refreshAdminAcls] [-refreshServiceAcl] [-getGroup" +
290               " [username]] [[-addToClusterNodeLabels [label1,label2,label3]]" +
291               " [-removeFromClusterNodeLabels [label1,label2,label3]] [-replaceLabelsOnNode " +
292               "[node1[:port]=label1,label2 node2[:port]=label1] [-directlyAccessNodeLabelStore]] " +
293               "[-help [cmd]]"));
294       assertTrue(dataOut
295           .toString()
296           .contains(
297               "-refreshQueues: Reload the queues' acls, states and scheduler " +
298               "specific properties."));
299       assertTrue(dataOut
300           .toString()
301           .contains(
302               "-refreshNodes: Refresh the hosts information at the " +
303               "ResourceManager."));
304       assertTrue(dataOut.toString().contains(
305           "-refreshUserToGroupsMappings: Refresh user-to-groups mappings"));
306       assertTrue(dataOut
307           .toString()
308           .contains(
309               "-refreshSuperUserGroupsConfiguration: Refresh superuser proxy" +
310               " groups mappings"));
311       assertTrue(dataOut
312           .toString()
313           .contains(
314               "-refreshAdminAcls: Refresh acls for administration of " +
315               "ResourceManager"));
316       assertTrue(dataOut
317           .toString()
318           .contains(
319               "-refreshServiceAcl: Reload the service-level authorization" +
320               " policy file"));
321       assertTrue(dataOut
322           .toString()
323           .contains(
324               "-help [cmd]: Displays help for the given command or all " +
325               "commands if none"));
326 
327       testError(new String[] { "-help", "-refreshQueues" },
328           "Usage: yarn rmadmin [-refreshQueues]", dataErr, 0);
329       testError(new String[] { "-help", "-refreshNodes" },
330           "Usage: yarn rmadmin [-refreshNodes]", dataErr, 0);
331       testError(new String[] { "-help", "-refreshUserToGroupsMappings" },
332           "Usage: yarn rmadmin [-refreshUserToGroupsMappings]", dataErr, 0);
333       testError(
334           new String[] { "-help", "-refreshSuperUserGroupsConfiguration" },
335           "Usage: yarn rmadmin [-refreshSuperUserGroupsConfiguration]",
336           dataErr, 0);
337       testError(new String[] { "-help", "-refreshAdminAcls" },
338           "Usage: yarn rmadmin [-refreshAdminAcls]", dataErr, 0);
339       testError(new String[] { "-help", "-refreshServiceAcl" },
340           "Usage: yarn rmadmin [-refreshServiceAcl]", dataErr, 0);
341       testError(new String[] { "-help", "-getGroups" },
342           "Usage: yarn rmadmin [-getGroups [username]]", dataErr, 0);
343       testError(new String[] { "-help", "-transitionToActive" },
344           "Usage: yarn rmadmin [-transitionToActive [--forceactive]" +
345           " <serviceId>]", dataErr, 0);
346       testError(new String[] { "-help", "-transitionToStandby" },
347           "Usage: yarn rmadmin [-transitionToStandby <serviceId>]", dataErr, 0);
348       testError(new String[] { "-help", "-getServiceState" },
349           "Usage: yarn rmadmin [-getServiceState <serviceId>]", dataErr, 0);
350       testError(new String[] { "-help", "-checkHealth" },
351           "Usage: yarn rmadmin [-checkHealth <serviceId>]", dataErr, 0);
352       testError(new String[] { "-help", "-failover" },
353           "Usage: yarn rmadmin " +
354               "[-failover [--forcefence] [--forceactive] " +
355               "<serviceId> <serviceId>]",
356           dataErr, 0);
357 
358       testError(new String[] { "-help", "-badParameter" },
359           "Usage: yarn rmadmin", dataErr, 0);
360       testError(new String[] { "-badParameter" },
361           "badParameter: Unknown command", dataErr, -1);
362 
363       // Test -help when RM HA is enabled
364       assertEquals(0, rmAdminCLIWithHAEnabled.run(args));
365       oldOutPrintStream.println(dataOut);
366       String expectedHelpMsg =
367           "yarn rmadmin [-refreshQueues] [-refreshNodes] [-refreshSuper" +
368               "UserGroupsConfiguration] [-refreshUserToGroupsMappings] " +
369               "[-refreshAdminAcls] [-refreshServiceAcl] [-getGroup" +
370               " [username]] [[-addToClusterNodeLabels [label1,label2,label3]]" +
371               " [-removeFromClusterNodeLabels [label1,label2,label3]] [-replaceLabelsOnNode " +
372               "[node1[:port]=label1,label2 node2[:port]=label1] [-directlyAccessNodeLabelStore]] " +
373               "[-transitionToActive [--forceactive] <serviceId>] " +
374               "[-transitionToStandby <serviceId>] [-failover" +
375               " [--forcefence] [--forceactive] <serviceId> <serviceId>] " +
376               "[-getServiceState <serviceId>] [-checkHealth <serviceId>] [-help [cmd]]";
377       String actualHelpMsg = dataOut.toString();
378       assertTrue(String.format("Help messages: %n " + actualHelpMsg + " %n doesn't include expected " +
379           "messages: %n" + expectedHelpMsg), actualHelpMsg.contains(expectedHelpMsg
380               ));
381     } finally {
382       System.setOut(oldOutPrintStream);
383       System.setErr(oldErrPrintStream);
384     }
385   }
386 
387   @Test(timeout=500)
testException()388   public void testException() throws Exception {
389     PrintStream oldErrPrintStream = System.err;
390     ByteArrayOutputStream dataErr = new ByteArrayOutputStream();
391     System.setErr(new PrintStream(dataErr));
392     try {
393       when(admin.refreshQueues(any(RefreshQueuesRequest.class)))
394           .thenThrow(new IOException("test exception"));
395       String[] args = { "-refreshQueues" };
396 
397       assertEquals(-1, rmAdminCLI.run(args));
398       verify(admin).refreshQueues(any(RefreshQueuesRequest.class));
399       assertTrue(dataErr.toString().contains("refreshQueues: test exception"));
400     } finally {
401       System.setErr(oldErrPrintStream);
402     }
403   }
404 
405   @Test
testAccessLocalNodeLabelManager()406   public void testAccessLocalNodeLabelManager() throws Exception {
407     assertFalse(dummyNodeLabelsManager.getServiceState() == STATE.STOPPED);
408 
409     String[] args =
410         { "-addToClusterNodeLabels", "x,y", "-directlyAccessNodeLabelStore" };
411     assertEquals(0, rmAdminCLI.run(args));
412     assertTrue(dummyNodeLabelsManager.getClusterNodeLabels().containsAll(
413         ImmutableSet.of("x", "y")));
414 
415     // reset localNodeLabelsManager
416     dummyNodeLabelsManager.removeFromClusterNodeLabels(ImmutableSet.of("x", "y"));
417 
418     // change the sequence of "-directlyAccessNodeLabelStore" and labels,
419     // should not matter
420     args =
421         new String[] { "-addToClusterNodeLabels",
422             "-directlyAccessNodeLabelStore", "x,y" };
423     assertEquals(0, rmAdminCLI.run(args));
424     assertTrue(dummyNodeLabelsManager.getClusterNodeLabels().containsAll(
425         ImmutableSet.of("x", "y")));
426 
427     // local node labels manager will be close after running
428     assertTrue(dummyNodeLabelsManager.getServiceState() == STATE.STOPPED);
429   }
430 
431   @Test
testAccessRemoteNodeLabelManager()432   public void testAccessRemoteNodeLabelManager() throws Exception {
433     String[] args =
434         { "-addToClusterNodeLabels", "x,y" };
435     assertEquals(0, rmAdminCLI.run(args));
436 
437     // localNodeLabelsManager shouldn't accessed
438     assertTrue(dummyNodeLabelsManager.getClusterNodeLabels().isEmpty());
439 
440     // remote node labels manager accessed
441     assertTrue(remoteAdminServiceAccessed);
442   }
443 
444   @Test
testAddToClusterNodeLabels()445   public void testAddToClusterNodeLabels() throws Exception {
446     // successfully add labels
447     String[] args =
448         { "-addToClusterNodeLabels", "x", "-directlyAccessNodeLabelStore" };
449     assertEquals(0, rmAdminCLI.run(args));
450     assertTrue(dummyNodeLabelsManager.getClusterNodeLabels().containsAll(
451         ImmutableSet.of("x")));
452 
453     // no labels, should fail
454     args = new String[] { "-addToClusterNodeLabels" };
455     assertTrue(0 != rmAdminCLI.run(args));
456 
457     // no labels, should fail
458     args =
459         new String[] { "-addToClusterNodeLabels",
460             "-directlyAccessNodeLabelStore" };
461     assertTrue(0 != rmAdminCLI.run(args));
462 
463     // no labels, should fail at client validation
464     args = new String[] { "-addToClusterNodeLabels", " " };
465     assertTrue(0 != rmAdminCLI.run(args));
466 
467     // no labels, should fail at client validation
468     args = new String[] { "-addToClusterNodeLabels", " , " };
469     assertTrue(0 != rmAdminCLI.run(args));
470 
471     // successfully add labels
472     args =
473         new String[] { "-addToClusterNodeLabels", ",x,,",
474             "-directlyAccessNodeLabelStore" };
475     assertEquals(0, rmAdminCLI.run(args));
476     assertTrue(dummyNodeLabelsManager.getClusterNodeLabels().containsAll(
477         ImmutableSet.of("x")));
478   }
479 
480   @Test
testRemoveFromClusterNodeLabels()481   public void testRemoveFromClusterNodeLabels() throws Exception {
482     // Successfully remove labels
483     dummyNodeLabelsManager.addToCluserNodeLabels(ImmutableSet.of("x", "y"));
484     String[] args =
485         { "-removeFromClusterNodeLabels", "x,,y",
486             "-directlyAccessNodeLabelStore" };
487     assertEquals(0, rmAdminCLI.run(args));
488     assertTrue(dummyNodeLabelsManager.getClusterNodeLabels().isEmpty());
489 
490     // no labels, should fail
491     args = new String[] { "-removeFromClusterNodeLabels" };
492     assertTrue(0 != rmAdminCLI.run(args));
493 
494     // no labels, should fail
495     args =
496         new String[] { "-removeFromClusterNodeLabels",
497             "-directlyAccessNodeLabelStore" };
498     assertTrue(0 != rmAdminCLI.run(args));
499 
500     // no labels, should fail at client validation
501     args = new String[] { "-removeFromClusterNodeLabels", " " };
502     assertTrue(0 != rmAdminCLI.run(args));
503 
504     // no labels, should fail at client validation
505     args = new String[] { "-removeFromClusterNodeLabels", ", " };
506     assertTrue(0 != rmAdminCLI.run(args));
507   }
508 
509   @Test
testReplaceLabelsOnNode()510   public void testReplaceLabelsOnNode() throws Exception {
511     // Successfully replace labels
512     dummyNodeLabelsManager
513         .addToCluserNodeLabels(ImmutableSet.of("x", "y", "Y"));
514     String[] args =
515         { "-replaceLabelsOnNode",
516             "node1:8000,x node2:8000=y node3,x node4=Y",
517             "-directlyAccessNodeLabelStore" };
518     assertEquals(0, rmAdminCLI.run(args));
519     assertTrue(dummyNodeLabelsManager.getNodeLabels().containsKey(
520         NodeId.newInstance("node1", 8000)));
521     assertTrue(dummyNodeLabelsManager.getNodeLabels().containsKey(
522         NodeId.newInstance("node2", 8000)));
523     assertTrue(dummyNodeLabelsManager.getNodeLabels().containsKey(
524         NodeId.newInstance("node3", 0)));
525     assertTrue(dummyNodeLabelsManager.getNodeLabels().containsKey(
526         NodeId.newInstance("node4", 0)));
527 
528     // no labels, should fail
529     args = new String[] { "-replaceLabelsOnNode" };
530     assertTrue(0 != rmAdminCLI.run(args));
531 
532     // no labels, should fail
533     args =
534         new String[] { "-replaceLabelsOnNode", "-directlyAccessNodeLabelStore" };
535     assertTrue(0 != rmAdminCLI.run(args));
536 
537     // no labels, should fail
538     args = new String[] { "-replaceLabelsOnNode", " " };
539     assertTrue(0 != rmAdminCLI.run(args));
540 
541     args = new String[] { "-replaceLabelsOnNode", ", " };
542     assertTrue(0 != rmAdminCLI.run(args));
543   }
544 
545   @Test
testReplaceMultipleLabelsOnSingleNode()546   public void testReplaceMultipleLabelsOnSingleNode() throws Exception {
547     // Successfully replace labels
548     dummyNodeLabelsManager.addToCluserNodeLabels(ImmutableSet.of("x", "y"));
549     String[] args =
550         { "-replaceLabelsOnNode", "node1,x,y",
551             "-directlyAccessNodeLabelStore" };
552     assertTrue(0 != rmAdminCLI.run(args));
553   }
554 
testError(String[] args, String template, ByteArrayOutputStream data, int resultCode)555   private void testError(String[] args, String template,
556       ByteArrayOutputStream data, int resultCode) throws Exception {
557     int actualResultCode = rmAdminCLI.run(args);
558     assertEquals("Expected result code: " + resultCode +
559         ", actual result code is: " + actualResultCode, resultCode, actualResultCode);
560     assertTrue(String.format("Expected error message: %n" + template +
561         " is not included in messages: %n" + data.toString()),
562         data.toString().contains(template));
563     data.reset();
564   }
565 
566   @Test
testRMHAErrorUsage()567   public void testRMHAErrorUsage() throws Exception {
568     ByteArrayOutputStream errOutBytes = new ByteArrayOutputStream();
569     rmAdminCLIWithHAEnabled.setErrOut(new PrintStream(errOutBytes));
570     try {
571       String[] args = { "-failover" };
572       assertEquals(-1, rmAdminCLIWithHAEnabled.run(args));
573       String errOut = new String(errOutBytes.toByteArray(), Charsets.UTF_8);
574       errOutBytes.reset();
575       assertTrue(errOut.contains("Usage: rmadmin"));
576     } finally {
577       rmAdminCLIWithHAEnabled.setErrOut(System.err);
578     }
579   }
580 
581 }
582