You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by yu...@apache.org on 2014/08/30 02:16:04 UTC

git commit: AMBARI-6027. Add the capability of starting and stoping services with Ambari Shell. (Janos Matyas and Krisztian Horvath via yusaku)

Repository: ambari
Updated Branches:
  refs/heads/trunk 733f0345c -> 5ceeeb52b


AMBARI-6027. Add the capability of starting and stoping services with Ambari Shell. (Janos Matyas and Krisztian Horvath via yusaku)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/5ceeeb52
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/5ceeeb52
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/5ceeeb52

Branch: refs/heads/trunk
Commit: 5ceeeb52b9478ad5af86d4346a5d5bb7050462e9
Parents: 733f034
Author: Yusaku Sako <yu...@hortonworks.com>
Authored: Fri Aug 29 17:14:42 2014 -0700
Committer: Yusaku Sako <yu...@hortonworks.com>
Committed: Fri Aug 29 17:14:42 2014 -0700

----------------------------------------------------------------------
 .../ambari/groovy/client/AmbariClient.groovy    |  32 +++-
 .../groovy/client/AmbariServicesTest.groovy     |  63 ++++++++
 .../ambari/shell/commands/BasicCommands.java    |  74 ---------
 .../ambari/shell/commands/ServiceCommands.java  | 155 +++++++++++++++++++
 .../apache/ambari/shell/completion/Service.java |  31 ++++
 .../configuration/ConverterConfiguration.java   |   6 +
 .../shell/converter/ServiceConverter.java       |  55 +++++++
 .../shell/commands/ServiceCommandsTest.java     |  70 +++++++++
 8 files changed, 408 insertions(+), 78 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/5ceeeb52/ambari-client/groovy-client/src/main/groovy/org/apache/ambari/groovy/client/AmbariClient.groovy
----------------------------------------------------------------------
diff --git a/ambari-client/groovy-client/src/main/groovy/org/apache/ambari/groovy/client/AmbariClient.groovy b/ambari-client/groovy-client/src/main/groovy/org/apache/ambari/groovy/client/AmbariClient.groovy
index 1a515f5..f0ca650 100644
--- a/ambari-client/groovy-client/src/main/groovy/org/apache/ambari/groovy/client/AmbariClient.groovy
+++ b/ambari-client/groovy-client/src/main/groovy/org/apache/ambari/groovy/client/AmbariClient.groovy
@@ -781,7 +781,7 @@ class AmbariClient {
    */
   def int startAllServices() {
     log.debug("Starting all services ...")
-    manageAllServices("Start All Services", "STARTED")
+    manageService("Start All Services", "STARTED")
   }
 
   /**
@@ -791,7 +791,27 @@ class AmbariClient {
    */
   def int stopAllServices() {
     log.debug("Stopping all services ...")
-    manageAllServices("Stop All Services", "INSTALLED")
+    manageService("Stop All Services", "INSTALLED")
+  }
+
+  /**
+   * Starts the given service.
+   *
+   * @param service name of the service
+   * @return id of the request
+   */
+  def int startService(String service) {
+    manageService("Starting $service", "STARTED", service)
+  }
+
+  /**
+   * Stops the given service.
+   *
+   * @param service name of the service
+   * @return id of the request
+   */
+  def int stopService(String service) {
+    manageService("Stopping $service", "INSTALLED", service)
   }
 
   def boolean servicesStarted() {
@@ -868,15 +888,19 @@ class AmbariClient {
     return allInState;
   }
 
-  def private manageAllServices(String context, String state) {
+  def private manageService(String context, String state, String service = "") {
     Map bodyMap = [
       RequestInfo: [context: context],
       ServiceInfo: [state: state]
     ]
     JsonBuilder builder = new JsonBuilder(bodyMap)
+    def path = "${ambari.getUri()}clusters/${getClusterName()}/services"
+    if (service) {
+      path += "/$service"
+    }
     def Map<String, ?> putRequestMap = [:]
     putRequestMap.put('requestContentType', ContentType.URLENC)
-    putRequestMap.put('path', "${ambari.getUri()}" + "clusters/${getClusterName()}/services")
+    putRequestMap.put('path', path)
     putRequestMap.put('query', ['params/run_smoke_test': 'false'])
     putRequestMap.put('body', builder.toPrettyString());
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/5ceeeb52/ambari-client/groovy-client/src/test/groovy/org/apache/ambari/groovy/client/AmbariServicesTest.groovy
----------------------------------------------------------------------
diff --git a/ambari-client/groovy-client/src/test/groovy/org/apache/ambari/groovy/client/AmbariServicesTest.groovy b/ambari-client/groovy-client/src/test/groovy/org/apache/ambari/groovy/client/AmbariServicesTest.groovy
index ce8060f..e798789 100644
--- a/ambari-client/groovy-client/src/test/groovy/org/apache/ambari/groovy/client/AmbariServicesTest.groovy
+++ b/ambari-client/groovy-client/src/test/groovy/org/apache/ambari/groovy/client/AmbariServicesTest.groovy
@@ -17,11 +17,14 @@
  */
 package org.apache.ambari.groovy.client
 
+import groovy.json.JsonSlurper
 import groovy.util.logging.Slf4j
 
 @Slf4j
 class AmbariServicesTest extends AbstractAmbariClientTest {
 
+  def slurper = new JsonSlurper()
+
   private enum Scenario {
     SERVICES, NO_SERVICES, NO_SERVICE_COMPONENTS
   }
@@ -114,6 +117,66 @@ class AmbariServicesTest extends AbstractAmbariClientTest {
     !result
   }
 
+  def "test stop all services"() {
+    given:
+    def context
+    ambari.metaClass.getClusterName = { return "cluster" }
+    ambari.getAmbari().metaClass.put = { Map request ->
+      context = request
+    }
+    ambari.getSlurper().metaClass.parseText { String text -> return ["Requests": ["id": 1]] }
+
+    when:
+    def id = ambari.stopAllServices()
+
+    then:
+    1 == id
+    context.path == "http://localhost:8080/api/v1/clusters/cluster/services"
+    def body = slurper.parseText(context.body)
+    body.RequestInfo.context == "Stop All Services"
+    body.ServiceInfo.state == "INSTALLED"
+  }
+
+  def "test start service ZOOKEEPER"() {
+    given:
+    def context
+    ambari.metaClass.getClusterName = { return "cluster" }
+    ambari.getAmbari().metaClass.put = { Map request ->
+      context = request
+    }
+    ambari.getSlurper().metaClass.parseText { String text -> return ["Requests": ["id": 1]] }
+
+    when:
+    def id = ambari.startService("ZOOKEEPER")
+
+    then:
+    1 == id
+    context.path == "http://localhost:8080/api/v1/clusters/cluster/services/ZOOKEEPER"
+    def body = slurper.parseText(context.body)
+    body.RequestInfo.context == "Starting ZOOKEEPER"
+    body.ServiceInfo.state == "STARTED"
+  }
+
+  def "test stop service ZOOKEEPER"() {
+    given:
+    def context
+    ambari.metaClass.getClusterName = { return "cluster" }
+    ambari.getAmbari().metaClass.put = { Map request ->
+      context = request
+    }
+    ambari.getSlurper().metaClass.parseText { String text -> return ["Requests": ["id": 1]] }
+
+    when:
+    def id = ambari.stopService("ZOOKEEPER")
+
+    then:
+    1 == id
+    context.path == "http://localhost:8080/api/v1/clusters/cluster/services/ZOOKEEPER"
+    def body = slurper.parseText(context.body)
+    body.RequestInfo.context == "Stopping ZOOKEEPER"
+    body.ServiceInfo.state == "INSTALLED"
+  }
+
   def private String selectResponseJson(Map resourceRequestMap, String scenarioStr) {
     def thePath = resourceRequestMap.get("path");
     def Scenario scenario = Scenario.valueOf(scenarioStr)

http://git-wip-us.apache.org/repos/asf/ambari/blob/5ceeeb52/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java
index 9babe12..543ad15 100644
--- a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java
@@ -17,7 +17,6 @@
  */
 package org.apache.ambari.shell.commands;
 
-import static org.apache.ambari.shell.support.TableRenderer.renderMapValueMap;
 import static org.apache.ambari.shell.support.TableRenderer.renderSingleMap;
 
 import org.apache.ambari.groovy.client.AmbariClient;
@@ -70,46 +69,6 @@ public class BasicCommands implements CommandMarker {
   }
 
   /**
-   * Checks whether the service list command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator("services list")
-  public boolean isServiceListCommandAvailable() {
-    return context.isConnectedToCluster();
-  }
-
-  /**
-   * Prints the available service list of the Ambari Server.
-   *
-   * @return service list
-   */
-  @CliCommand(value = "services list", help = "Lists the available services")
-  public String servicesList() {
-    return renderSingleMap(client.getServicesMap(), "SERVICE", "STATE");
-  }
-
-  /**
-   * Checks whether the service components command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator("services components")
-  public boolean isServiceComponentsCommandAvailable() {
-    return context.isConnectedToCluster();
-  }
-
-  /**
-   * Prints the service components of the Ambari Server.
-   *
-   * @return service component list
-   */
-  @CliCommand(value = "services components", help = "Lists all services with their components")
-  public String serviceComponents() {
-    return renderMapValueMap(client.getServiceComponentsMap(), "SERVICE", "COMPONENT", "STATE");
-  }
-
-  /**
    * Checks whether the debug on command is available or not.
    *
    * @return true if available false otherwise
@@ -171,37 +130,4 @@ public class BasicCommands implements CommandMarker {
     return context.getHint();
   }
 
-  @CliAvailabilityIndicator("services stop")
-  public boolean isServiceStopCommandAvailable() {
-    return context.isConnectedToCluster();
-  }
-
-  @CliCommand(value = "services stop", help = "Stops all the running services")
-  public String stopServices() {
-    String message;
-    try {
-      client.stopAllServices();
-      message = "Stopping all services..";
-    } catch (Exception e) {
-      message = "Cannot stop services";
-    }
-    return String.format("%s\n\n%s", message, servicesList());
-  }
-
-  @CliAvailabilityIndicator("services start")
-  public boolean isServiceStartCommandAvailable() {
-    return context.isConnectedToCluster();
-  }
-
-  @CliCommand(value = "services start", help = "Starts all the services")
-  public String startServices() {
-    String message;
-    try {
-      client.startAllServices();
-      message = "Starting all services..";
-    } catch (Exception e) {
-      message = "Cannot start services";
-    }
-    return String.format("%s\n\n%s", message, servicesList());
-  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/5ceeeb52/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ServiceCommands.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ServiceCommands.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ServiceCommands.java
new file mode 100644
index 0000000..a598fe8
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ServiceCommands.java
@@ -0,0 +1,155 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.shell.commands;
+
+import static org.apache.ambari.shell.support.TableRenderer.renderMapValueMap;
+import static org.apache.ambari.shell.support.TableRenderer.renderSingleMap;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.completion.Service;
+import org.apache.ambari.shell.model.AmbariContext;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.shell.core.CommandMarker;
+import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+import org.springframework.stereotype.Component;
+
+/**
+ * Service related commands used in the shell.
+ *
+ * @see org.apache.ambari.groovy.client.AmbariClient
+ */
+@Component
+public class ServiceCommands implements CommandMarker {
+
+  private AmbariClient client;
+  private AmbariContext context;
+
+  @Autowired
+  public ServiceCommands(AmbariClient client, AmbariContext context) {
+    this.client = client;
+    this.context = context;
+  }
+
+  /**
+   * Checks whether the services list command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("services list")
+  public boolean isServiceListCommandAvailable() {
+    return context.isConnectedToCluster();
+  }
+
+  /**
+   * Prints the available services list of the Ambari Server.
+   *
+   * @return service list
+   */
+  @CliCommand(value = "services list", help = "Lists the available services")
+  public String servicesList() {
+    return renderSingleMap(client.getServicesMap(), "SERVICE", "STATE");
+  }
+
+  /**
+   * Checks whether the services components command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("services components")
+  public boolean isServiceComponentsCommandAvailable() {
+    return context.isConnectedToCluster();
+  }
+
+  /**
+   * Prints the services components of the Ambari Server.
+   *
+   * @return service component list
+   */
+  @CliCommand(value = "services components", help = "Lists all services with their components")
+  public String serviceComponents() {
+    return renderMapValueMap(client.getServiceComponentsMap(), "SERVICE", "COMPONENT", "STATE");
+  }
+
+  /**
+   * Checks whether the services stop command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("services stop")
+  public boolean isServiceStopCommandAvailable() {
+    return context.isConnectedToCluster();
+  }
+
+  /**
+   * Stops a service or all services if no service name is provided.
+   *
+   * @return service list
+   */
+  @CliCommand(value = "services stop", help = "Stops a service/all the running services")
+  public String stopServices(@CliOption(key = "service", mandatory = false, help = "Name of the service to stop") Service service) {
+    String message;
+    try {
+      if (service != null) {
+        String serviceName = service.getName();
+        message = "Stopping " + serviceName;
+        client.stopService(serviceName);
+      } else {
+        message = "Stopping all services..";
+        client.stopAllServices();
+      }
+    } catch (Exception e) {
+      message = "Cannot stop services";
+    }
+    return String.format("%s\n\n%s", message, servicesList());
+  }
+
+  /**
+   * Checks whether the services start command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("services start")
+  public boolean isServiceStartCommandAvailable() {
+    return context.isConnectedToCluster();
+  }
+
+  /**
+   * Starts a service or all services if no service name is provided.
+   *
+   * @return service list
+   */
+  @CliCommand(value = "services start", help = "Starts a service/all the services")
+  public String startServices(@CliOption(key = "service", mandatory = false, help = "Name of the service to start") Service service) {
+    String message;
+    try {
+      if (service != null) {
+        String serviceName = service.getName();
+        message = "Starting " + serviceName;
+        client.startService(serviceName);
+      } else {
+        client.startAllServices();
+        message = "Starting all services..";
+      }
+    } catch (Exception e) {
+      message = "Cannot start services";
+    }
+    return String.format("%s\n\n%s", message, servicesList());
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/5ceeeb52/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Service.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Service.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Service.java
new file mode 100644
index 0000000..bbbf37c
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Service.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.shell.completion;
+
+public class Service {
+
+  private final String name;
+
+  public Service(String name) {
+    this.name = name;
+  }
+
+  public String getName() {
+    return name;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/5ceeeb52/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ConverterConfiguration.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ConverterConfiguration.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ConverterConfiguration.java
index 049c52f..c19aced 100644
--- a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ConverterConfiguration.java
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ConverterConfiguration.java
@@ -20,6 +20,7 @@ package org.apache.ambari.shell.configuration;
 import org.apache.ambari.groovy.client.AmbariClient;
 import org.apache.ambari.shell.converter.BlueprintConverter;
 import org.apache.ambari.shell.converter.HostConverter;
+import org.apache.ambari.shell.converter.ServiceConverter;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -139,4 +140,9 @@ public class ConverterConfiguration {
   Converter hostConverter() {
     return new HostConverter(client);
   }
+
+  @Bean
+  Converter serviceConverter() {
+    return new ServiceConverter(client);
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/5ceeeb52/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/ServiceConverter.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/ServiceConverter.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/ServiceConverter.java
new file mode 100644
index 0000000..e7f9d2c
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/ServiceConverter.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.shell.converter;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.completion.Service;
+import org.springframework.shell.core.Completion;
+import org.springframework.shell.core.Converter;
+import org.springframework.shell.core.MethodTarget;
+
+public class ServiceConverter implements Converter<Service> {
+
+  private AmbariClient client;
+
+  public ServiceConverter(AmbariClient client) {
+    this.client = client;
+  }
+
+  @Override
+  public boolean supports(Class<?> type, String optionContext) {
+    return Service.class.isAssignableFrom(type);
+  }
+
+  @Override
+  public Service convertFromText(String value, Class<?> targetType, String optionContext) {
+    return new Service(value);
+  }
+
+  @Override
+  public boolean getAllPossibleValues(List<Completion> completions, Class<?> targetType, String existingData, String optionContext, MethodTarget target) {
+    Set<String> services = client.getServicesMap().keySet();
+    for (String service : services) {
+      completions.add(new Completion(service));
+    }
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/5ceeeb52/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/commands/ServiceCommandsTest.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/commands/ServiceCommandsTest.java b/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/commands/ServiceCommandsTest.java
new file mode 100644
index 0000000..6e39139
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/commands/ServiceCommandsTest.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.shell.commands;
+
+import static org.mockito.Mockito.verify;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.completion.Service;
+import org.apache.ambari.shell.model.AmbariContext;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ServiceCommandsTest {
+
+  @InjectMocks
+  private ServiceCommands serviceCommands;
+
+  @Mock
+  private AmbariClient client;
+  @Mock
+  private AmbariContext context;
+
+  @Test
+  public void testStopAllServices() {
+    serviceCommands.stopServices(null);
+
+    verify(client).stopAllServices();
+  }
+
+  @Test
+  public void testStopService() {
+    serviceCommands.stopServices(new Service("ZOOKEEPER"));
+
+    verify(client).stopService("ZOOKEEPER");
+  }
+
+  @Test
+  public void testStartAllServices() {
+    serviceCommands.startServices(null);
+
+    verify(client).startAllServices();
+  }
+
+  @Test
+  public void testStartService() {
+    serviceCommands.startServices(new Service("ZOOKEEPER"));
+
+    verify(client).startService("ZOOKEEPER");
+  }
+
+}