فهرست منبع

AMBARI-2461. Add unit tests for bootstrap and setupAgent python scripts for the server. (Dmytro Sh via mahadev)

git-svn-id: https://svn.apache.org/repos/asf/incubator/ambari/trunk@1499024 13f79535-47bb-0310-9956-ffa450edef68
Mahadev Konar 12 سال پیش
والد
کامیت
e6243e3402

+ 14 - 18
ambari-server/src/main/python/bootstrap.py

@@ -125,10 +125,6 @@ class SSH(threading.Thread):
     logFile = open(logFilePath, "a+")
     logFile.write(self.ret["log"])
     logFile.close
-    pass
-
-pass
-
 
 def splitlist(hosts, n):
   return [hosts[i:i+n] for i in range(0, len(hosts), n)]
@@ -269,7 +265,8 @@ class BootStrap:
 
   
   """ BootStrapping the agents on a list of hosts"""
-  def __init__(self, hosts, user, sshkeyFile, scriptDir, boottmpdir, setupAgentFile, ambariServer, cluster_os_type, ambariVersion, server_port, passwordFile = None):
+  def __init__(self, hosts, user, sshkeyFile, scriptDir, boottmpdir, setupAgentFile, ambariServer, cluster_os_type,\
+               ambariVersion, server_port, passwordFile = None):
     self.hostlist = hosts
     self.successive_hostlist = hosts
     self.hostlist_to_remove_password_file = None
@@ -285,7 +282,8 @@ class BootStrap:
     self.statuses = None
     self.server_port = server_port
     """Prepare temp file names"""
-    self.osCheckScriptRemoteLocation = os.path.join(self.TEMP_FOLDER, self.generateRandomFileName(self.OS_CHECK_SCRIPT_FILE_TEMPLATE))
+    self.osCheckScriptRemoteLocation = os.path.join(self.TEMP_FOLDER,\
+                                                    self.generateRandomFileName(self.OS_CHECK_SCRIPT_FILE_TEMPLATE))
     pass
 
   def generateRandomFileName(self, fileNameTemplate):
@@ -323,9 +321,6 @@ class BootStrap:
   def getOsCheckScriptRemoteLocation(self):
     return self.osCheckScriptRemoteLocation
 
-  def getSetupScript(self):
-    return os.path.join(self.scriptDir, "setupAgent.py")
-
   def getUtime(self):
     return int(time.time())
 
@@ -526,7 +521,9 @@ class BootStrap:
     try:
       """ Checking 'sudo' package on remote hosts """
       command = "rpm -qa | grep sudo"
-      pssh = PSSH(self.successive_hostlist, self.user, self.sshkeyFile, self.bootdir, errorMessage="Error: Sudo command is not available. Please install the sudo command.", command=command)
+      pssh = PSSH(self.successive_hostlist, self.user, self.sshkeyFile, self.bootdir,\
+                  errorMessage="Error: Sudo command is not available. Please install the sudo command.",\
+                  command=command)
       pssh.run()
       out = pssh.getstatus()
       # Preparing report about failed hosts
@@ -591,7 +588,6 @@ class BootStrap:
     except Exception, e:
       logging.info("Traceback " + traceback.format_exc())
       return 1
-    pass
 
   def changePasswordFileModeOnHost(self):
     try:
@@ -620,7 +616,6 @@ class BootStrap:
     except Exception, e:
       logging.info("Traceback " + traceback.format_exc())
       return 1
-    pass
 
   def deletePasswordFile(self):
     try:
@@ -649,7 +644,6 @@ class BootStrap:
     except Exception, e:
       logging.info("Traceback " + traceback.format_exc())
       return 1
-    pass
 
   def run(self):
     """ Copyfiles and run commands on remote hosts """
@@ -684,9 +678,9 @@ def main(argv=None):
   onlyargs = argv[1:]
   if len(onlyargs) < 3:
     sys.stderr.write("Usage: <comma separated hosts> "
-                     "<tmpdir for storage> <user> <sshkeyFile> <agent setup script> <ambari-server name> <cluster os type> <ambari version> <ambari port> <passwordFile>\n")
+                     "<tmpdir for storage> <user> <sshkeyFile> <agent setup script>"
+                     " <ambari-server name> <cluster os type> <ambari version> <ambari port> <passwordFile>\n")
     sys.exit(2)
-    pass
   #Parse the input
   hostList = onlyargs[0].split(",")
   bootdir =  onlyargs[1]
@@ -707,9 +701,11 @@ def main(argv=None):
   
   logging.info("BootStrapping hosts " + pprint.pformat(hostList) +
                "using " + scriptDir + " cluster primary OS: " + cluster_os_type +
-              " with user '" + user + "' sshKey File " + sshKeyFile + " password File " + passwordFile +
-              " using tmp dir " + bootdir + " ambari: " + ambariServer +"; server_port: " + server_port + "; ambari version: " + ambariVersion)
-  bootstrap = BootStrap(hostList, user, sshKeyFile, scriptDir, bootdir, setupAgentFile, ambariServer, cluster_os_type, ambariVersion, server_port, passwordFile)
+               " with user '" + user + "' sshKey File " + sshKeyFile + " password File " + passwordFile +\
+               " using tmp dir " + bootdir + " ambari: " + ambariServer +"; server_port: " + server_port +\
+               "; ambari version: " + ambariVersion)
+  bootstrap = BootStrap(hostList, user, sshKeyFile, scriptDir, bootdir, setupAgentFile,\
+                        ambariServer, cluster_os_type, ambariVersion, server_port, passwordFile)
   ret = bootstrap.run()
   #return  ret
   return 0 # Hack to comply with current usage

+ 24 - 16
ambari-server/src/main/python/setupAgent.py

@@ -70,21 +70,22 @@ def installAgent(projectVersion):
 
 def configureAgent(server_hostname):
   """ Configure the agent so that it has all the configs knobs properly installed """
-  osCommand = ["sed", "-i.bak", "s/hostname=localhost/hostname=" + server_hostname + "/g", "/etc/ambari-agent/conf/ambari-agent.ini"]
+  osCommand = ["sed", "-i.bak", "s/hostname=localhost/hostname=" + server_hostname +\
+                                "/g", "/etc/ambari-agent/conf/ambari-agent.ini"]
   execOsCommand(osCommand)
-
   return
 
 def runAgent(passPhrase, expected_hostname):
   os.environ[AMBARI_PASSPHRASE_VAR] = passPhrase
-  agent_retcode = subprocess.call("/usr/sbin/ambari-agent restart --expected-hostname=" + expected_hostname, shell=True)
+  agent_retcode = subprocess.call("/usr/sbin/ambari-agent restart --expected-hostname=" +\
+                                  expected_hostname, shell=True)
   try:
-
     ret = execOsCommand(["tail", "-20", "/var/log/ambari-agent/ambari-agent.log"])
     try:
-      print ret['log']
-    except KeyError:
-      pass
+      log = ret['log']
+    except Exception:
+      log = "Log not found"
+    print log
     if not 0 == ret['exitstatus']:
       return ret['exitstatus']
 
@@ -94,8 +95,6 @@ def runAgent(passPhrase, expected_hostname):
 
 
 def getOptimalVersion(initialProjectVersion):
-  if initialProjectVersion == "":
-    return initialProjectVersion
   optimalVersion = initialProjectVersion
 
   if is_suse():
@@ -131,11 +130,13 @@ def checkAgentPackageAvailability(projectVersion):
   return execOsCommand(yumCommand)
 
 def findNearestAgentPackageVersionSuse(projectVersion):
-  zypperCommand = ["bash", "-c", "zypper search -s --match-exact ambari-agent | grep ' " + projectVersion + "' | cut -d '|' -f 4 | head -n1"]
+  zypperCommand = ["bash", "-c", "zypper search -s --match-exact ambari-agent | grep ' " + projectVersion +\
+                                 "' | cut -d '|' -f 4 | head -n1"]
   return execOsCommand(zypperCommand)
 
 def findNearestAgentPackageVersion(projectVersion):
-  yumCommand = ["bash", "-c", "yum list available ambari-agent | grep ' " + projectVersion + "' | sed -re 's/\s+/ /g' | cut -d ' ' -f 2 | head -n1"]
+  yumCommand = ["bash", "-c", "yum list available ambari-agent | grep ' " + projectVersion +\
+                              "' | sed -re 's/\s+/ /g' | cut -d ' ' -f 2 | head -n1"]
   return execOsCommand(yumCommand)
 
 def checkServerReachability(host, port):
@@ -144,9 +145,10 @@ def checkServerReachability(host, port):
   try: 
    s.connect((host, port)) 
    return
-  except socket.error, e: 
+  except Exception:
    ret["exitstatus"] = 1
-   ret["log"] = "Host registration aborted. Ambari Agent host cannot reach Ambari Server '" + host+":"+str(port) + "'. "+\
+   ret["log"] = "Host registration aborted. Ambari Agent host cannot reach Ambari Server '" +\
+                host+":"+str(port) + "'. "+\
   		        "Please check the network connectivity between the Ambari Agent host and the Ambari Server"
    sys.exit(ret)
   pass
@@ -179,10 +181,16 @@ def main(argv=None):
     projectVersion = "-" + projectVersion
 
   if is_suse():
-    installAgentSuse(projectVersion)
+    ret = installAgentSuse(projectVersion)
+    if (not ret["exitstatus"]==0):
+      sys.exit(ret)
   else:
-    installPreReq()
-    installAgent(projectVersion)
+    ret = installPreReq()
+    if (not ret["exitstatus"]==0):
+      sys.exit(ret)
+    ret = installAgent(projectVersion)
+    if (not ret["exitstatus"]==0):
+      sys.exit(ret)
 
   configureAgent(hostname)
   sys.exit(runAgent(passPhrase, expected_hostname))

+ 237 - 27
ambari-server/src/test/python/TestBootstrap.py

@@ -40,12 +40,14 @@ class TestBootstrap(TestCase):
     logging.basicConfig(level=logging.ERROR)
 
   #Timout is specified in bootstrap.HOST_BOOTSTRAP_TIMEOUT, default is 300 seconds
-  def test_return_failed_status_for_hanging_ssh_threads_after_timeout(self):
+  @patch.object(time, "time")
+  def test_return_failed_status_for_hanging_ssh_threads_after_timeout(self, time_mock):
     bootstrap.HOST_BOOTSTRAP_TIMEOUT = 1
     forever_hanging_timeout = 5
     SSH.run = lambda self: time.sleep(forever_hanging_timeout)
     pssh = PSSH(["hostname"], "root", "sshKeyFile", "bootdir", command="command")
     self.assertTrue(pssh.ret == {})
+    time_mock.side_effect = [0,0,500, forever_hanging_timeout-1]
     starttime = time.time()
     pssh.run()
     self.assertTrue(pssh.ret != {})
@@ -53,13 +55,36 @@ class TestBootstrap(TestCase):
     self.assertTrue(pssh.ret["hostname"]["log"] == "FAILED")
     self.assertTrue(pssh.ret["hostname"]["exitstatus"] == -1)
 
+  @patch.object(bootstrap, "get_difference")
+  @patch.object(PSCP, "run")
+  def test_copyPasswordFile(self, run_mock, get_difference_mock):
+    bootstrap_obj = BootStrap(["hostname"], "root", "sshKeyFile", "scriptDir",\
+                              "bootdir", "setupAgentFile", "ambariServer", "centos6", None, "8440")
+    bootstrap_obj.statuses = {
+        "hostname" : {
+            "exitstatus" : 0,
+            "log" : ""
+        }
+    }
+    get_difference_mock.return_value = ["hostname"]
+    ret = bootstrap_obj.copyPasswordFile()
+    self.assertTrue(ret == 1)
+    get_difference_mock.return_value = None
+    ret = bootstrap_obj.copyPasswordFile()
+    self.assertTrue(ret == 0)
+    bootstrap_obj.statuses = None
+    ret = bootstrap_obj.copyPasswordFile()
+    self.assertTrue(ret == 1)
+
   #Timout is specified in bootstrap.HOST_BOOTSTRAP_TIMEOUT, default is 300 seconds
-  def test_return_failed_status_for_hanging_scp_threads_after_timeout(self):
+  @patch.object(time, "time")
+  def test_return_failed_status_for_hanging_scp_threads_after_timeout(self, time_mock):
     bootstrap.HOST_BOOTSTRAP_TIMEOUT = 1
     forever_hanging_timeout = 5
     SCP.run = lambda self: time.sleep(forever_hanging_timeout)
     pscp = PSCP(["hostname"], "root", "sshKeyFile", "inputfile", "remote", "bootdir")
     self.assertTrue(pscp.ret == {})
+    time_mock.side_effect = [0,0,500, forever_hanging_timeout-1]
     starttime = time.time()
     pscp.run()
     self.assertTrue(pscp.ret != {})
@@ -67,24 +92,176 @@ class TestBootstrap(TestCase):
     self.assertTrue(pscp.ret["hostname"]["log"] == "FAILED")
     self.assertTrue(pscp.ret["hostname"]["exitstatus"] == -1)
 
+
+  @patch.object(bootstrap, "get_difference")
   @patch.object(SCP, "writeLogToFile")
   @patch.object(SSH, "writeLogToFile")
   @patch.object(Popen, "communicate")
   def test_return_error_message_for_missing_sudo_package(self, communicate_method,
                                                          SSH_writeLogToFile_method,
-                                                         SCP_writeLogToFile_method):
+                                                         SCP_writeLogToFile_method,
+                                                         get_difference_mock):
     SCP_writeLogToFile_method.return_value = None
     SSH_writeLogToFile_method.return_value = None
+    get_difference_mock.return_value = None
     communicate_method.return_value = ("", "")
-    bootstrap = BootStrap(["hostname"], "root", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "centos6", None, "8440")
-    bootstrap.statuses = {
+    bootstrap_obj = BootStrap(["hostname"], "root", "sshKeyFile", "scriptDir", "bootdir",\
+                              "setupAgentFile", "ambariServer", "centos6", None, "8440")
+    bootstrap_obj.statuses = {
       "hostname" : {
         "exitstatus" : 0,
         "log" : ""
       }
     }
-    ret = bootstrap.checkSudoPackage()
-    self.assertTrue("Error: Sudo command is not available. Please install the sudo command." in bootstrap.statuses["hostname"]["log"])
+    ret = bootstrap_obj.checkSudoPackage()
+    self.assertTrue("Error: Sudo command is not available. Please install the sudo command."\
+        in bootstrap_obj.statuses["hostname"]["log"])
+    bootstrap_obj.statuses = None
+    ret = bootstrap_obj.checkSudoPackage()
+    self.assertTrue(ret == None)
+    obj = MagicMock()
+    objtype = MagicMock()
+    func = bootstrap_obj.__get__(obj, objtype)
+    self.assertTrue(not func is None)
+    # This falls because returned function is not Bootstrap member
+    #func(MagicMock(), MagicMock())
+
+  @patch.object(bootstrap, "get_difference")
+  @patch.object(PSSH, "run")
+  def test_changePasswordFileModeOnHost(self, run_mock, get_difference_mock):
+    bootstrap_obj = BootStrap(["hostname"], "root", "sshKeyFile", "scriptDir", "bootdir",\
+                              "setupAgentFile", "ambariServer", "centos6", None, "8440")
+    ret = bootstrap_obj.changePasswordFileModeOnHost()
+    self.assertTrue(ret == 1)
+    bootstrap_obj.statuses = {
+        "hostname" : {
+            "exitstatus" : 0,
+            "log" : ""
+        }
+    }
+    ret = bootstrap_obj.changePasswordFileModeOnHost()
+    self.assertTrue(ret == 1)
+    get_difference_mock.return_value = None
+    ret = bootstrap_obj.changePasswordFileModeOnHost()
+    self.assertTrue(ret == 0)
+
+  @patch.object(bootstrap, "get_difference")
+  @patch.object(PSSH, "run")
+  def test_deletePasswordFile(self, run_mock, get_difference_mock):
+    bootstrap = BootStrap(["hostname"], "root", "sshKeyFile", "scriptDir", "bootdir",\
+                          "setupAgentFile", "ambariServer", "centos6", None, "8440")
+    ret = bootstrap.deletePasswordFile()
+    self.assertTrue(ret == 1)
+    bootstrap.statuses = {
+        "hostname" : {
+            "exitstatus" : 0,
+            "log" : ""
+        }
+    }
+    bootstrap.hostlist_to_remove_password_file = ["hostname"]
+    ret = bootstrap.deletePasswordFile()
+    self.assertTrue(ret == 1)
+    get_difference_mock.return_value = None
+    bootstrap.hostlist_to_remove_password_file = ["hostname"]
+    ret = bootstrap.deletePasswordFile()
+    self.assertTrue(ret == 0)
+
+  @patch("__builtin__.open")
+  def test_createDoneFiles(self, open_mock):
+    bootstrap_obj = BootStrap(["hostname"], "root", "sshKeyFile", "scriptDir", "bootdir",\
+                              "setupAgentFile", "ambariServer", "centos6", None, "8440")
+    bootstrap_obj.statuses = {"hostname": {"exitstatus" : 0}, "hostname1": {"exitstatus" : 0}}
+    f = open_mock.return_value
+    f.write = MagicMock()
+    ret = bootstrap_obj.createDoneFiles()
+    self.assertTrue(f.write.call_count == 2)
+
+
+  @patch.object(subprocess, "Popen")
+  @patch("sys.stderr")
+  @patch("sys.exit")
+  @patch.object(BootStrap, "run")
+  @patch("os.path.dirname")
+  @patch("os.path.realpath")
+  def test_bootstrap_main(self, dirname_mock, realpath_mock, run_mock, exit_mock, stderr_mock, subprocess_Popen_mock):
+    bootstrap.main(["bootstrap.py", "hostname,hostname2", "/tmp/bootstrap", "root", "sshKeyFile", "setupAgent.py", "ambariServer",\
+                    "centos6", "1.1.1", "8440", "passwordfile"])
+    self.assertTrue(run_mock.called)
+    run_mock.reset()
+    bootstrap.main(["bootstrap.py", "hostname,hostname2", "/tmp/bootstrap", "root", "sshKeyFile", "setupAgent.py", "ambariServer", \
+                    "centos6", "1.1.1", "8440", None])
+    self.assertTrue(run_mock.called)
+    run_mock.reset()
+    def side_effect(retcode):
+      raise Exception(retcode, "sys.exit")
+    exit_mock.side_effect = side_effect
+    try:
+     bootstrap.main(["bootstrap.py","hostname,hostname2", "/tmp/bootstrap"])
+     self.fail("sys.exit(2)")
+    except Exception:
+    # Expected
+     pass
+    self.assertTrue(exit_mock.called)
+
+
+  def test_getAmbariPort(self):
+    bootstrap_obj = BootStrap(["hostname"], "root", "sshKeyFile", "scriptDir", "bootdir",\
+                              "setupAgentFile", "ambariServer", "centos6", None, "8440")
+    self.assertEquals(bootstrap_obj.getAmbariPort(),"8440")
+    bootstrap_obj = BootStrap(["hostname"], "root", "sshKeyFile", "scriptDir", "bootdir",\
+                              "setupAgentFile", "ambariServer", "centos6", None, None)
+    self.assertEquals(bootstrap_obj.getAmbariPort(),"null")
+
+  def test_getRunSetupWithPasswordCommand(self):
+    bootstrap_obj = BootStrap(["hostname"], "root", "sshKeyFile", "scriptDir", "bootdir",\
+                              "setupAgentFile", "ambariServer", "centos6", None, "8440")
+    ret = bootstrap_obj.getRunSetupWithPasswordCommand("hostname")
+    self.assertEquals(ret, "sudo -S python /tmp/setupAgent.py hostname  ambariServer  8440 < /tmp/host_pass")
+
+  @patch("__builtin__.open")
+  def test_SCP_writeLogToFile(self, open_mock):
+    scp_obj = SCP(["hostaname"], "root", MagicMock(), MagicMock(), "/tmp", "/tmp/boot")
+    f = open_mock.return_value
+    scp_obj.writeLogToFile("/tmp")
+    self.assertTrue(f.write.called)
+
+  @patch("__builtin__.open")
+  def test_SSH_writeLogToFile(self, open_mock):
+      scp_obj = SSH(["hostaname"], "root", MagicMock(), MagicMock(), "/tmp", "/tmp/boot")
+      f = open_mock.return_value
+      scp_obj.writeLogToFile("/tmp")
+      self.assertTrue(f.write.called)
+
+  def test_generateRandomFileName(self):
+    bootstrap_obj = BootStrap(["hostname"], "root", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile",\
+                              "ambariServer", "centos6", None, "8440")
+    self.assertTrue(bootstrap_obj.generateRandomFileName(None) == bootstrap_obj.getUtime())
+
+  @patch("os.path.isfile")
+  @patch("__builtin__.open")
+  def test_is_suse(self, open_mock, isfile_mock):
+    bootstrap_obj = BootStrap(["hostname"], "root", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile",\
+                              "ambariServer", "centos6", None, "8440")
+    isfile_mock.return_value = True
+    f = open_mock.return_value
+    f.read.return_value = " suse  "
+    self.assertTrue(bootstrap_obj.is_suse())
+
+
+  @patch.object(BootStrap, "is_suse")
+  def test_getRepoDir(self, is_suse_mock):
+    bootstrap_obj = BootStrap(["hostname"], "root", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile",\
+                              "ambariServer", "centos6", None, "8440")
+    is_suse_mock.return_value = True
+    res = bootstrap_obj.getRepoDir()
+    self.assertEquals(res, "/etc/zypp/repos.d")
+
+  @patch("os.path.join")
+  def test_getSetupScript(self, join_mock):
+    bootstrap_obj = BootStrap(["hostname"], "root", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile",\
+                              "ambariServer", "centos6", None, "8440")
+    self.assertTrue(join_mock.called)
+    self.assertEquals(bootstrap_obj.scriptDir, "scriptDir")
 
   @patch.object(SCP, "writeLogToFile")
   @patch.object(SSH, "writeLogToFile")
@@ -109,7 +286,8 @@ class TestBootstrap(TestCase):
     changePasswordFileModeOnHost_method.return_value = 0
 
     os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
-    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "centos6", None, "8440", "passwordFile")
+    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile",\
+                          "ambariServer", "centos6", None, "8440", "passwordFile")
     def side_effect():
       bootstrap.copyPasswordFile_called = True
       bootstrap.hostlist_to_remove_password_file = ["hostname"]
@@ -142,7 +320,8 @@ class TestBootstrap(TestCase):
     changePasswordFileModeOnHost_method.return_value = 0
 
     os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
-    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "centos6", None, "8440")
+    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile",\
+                          "ambariServer", "centos6", None, "8440")
     bootstrap.copyPasswordFile_called = False
     def side_effect():
       bootstrap.copyPasswordFile_called = True
@@ -154,6 +333,7 @@ class TestBootstrap(TestCase):
     self.assertFalse(deletePasswordFile_method.called)
     self.assertFalse(changePasswordFileModeOnHost_method.called)
 
+  @patch.object(bootstrap, "get_difference")
   @patch.object(SCP, "writeLogToFile")
   @patch.object(SSH, "writeLogToFile")
   @patch.object(Popen, "communicate")
@@ -165,9 +345,11 @@ class TestBootstrap(TestCase):
                                                                     createDoneFiles_method,
                                                                     communicate_method,
                                                                     SSH_writeLogToFile_method,
-                                                                    SCP_writeLogToFile_method):
+                                                                    SCP_writeLogToFile_method,
+                                                                    get_difference_mock):
     SCP_writeLogToFile_method.return_value = None
     SSH_writeLogToFile_method.return_value = None
+    get_difference_mock.return_value = None
     communicate_method.return_value = ("", "")
     createDoneFiles_method.return_value = None
 
@@ -176,16 +358,26 @@ class TestBootstrap(TestCase):
 
     os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
     hosts = ["hostname"]
-    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "centos6", None, "8440", "passwordFile")
-    bootstrap.successive_hostlist = hosts
-    bootstrap.copyOsCheckScript()
-    bootstrap.successive_hostlist = hosts
-    bootstrap.copyNeededFiles()
-    bootstrap.successive_hostlist = hosts
-    bootstrap.runSetupAgent()
+    bootstrap_obj = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile",\
+                              "ambariServer", "centos6", None, "8440", "passwordFile")
+    bootstrap_obj.successive_hostlist = hosts
+    bootstrap_obj.copyOsCheckScript()
+    bootstrap_obj.successive_hostlist = hosts
+    bootstrap_obj.copyNeededFiles()
+    bootstrap_obj.successive_hostlist = hosts
+    bootstrap_obj.runSetupAgent()
+    self.assertTrue(getRunSetupWithPasswordCommand_method.called)
+    self.assertTrue(getMoveRepoFileWithPasswordCommand_method.called)
+    getRunSetupWithPasswordCommand_method.reset()
+    getMoveRepoFileWithPasswordCommand_method.reset()
+    getRunSetupWithPasswordCommand_method.reset()
+    getMoveRepoFileWithPasswordCommand_method.reset()
+    bootstrap_obj.successive_hostlist = None
+    bootstrap_obj.copyOsCheckScript()
     self.assertTrue(getRunSetupWithPasswordCommand_method.called)
     self.assertTrue(getMoveRepoFileWithPasswordCommand_method.called)
 
+  @patch.object(bootstrap, "get_difference")
   @patch.object(SCP, "writeLogToFile")
   @patch.object(SSH, "writeLogToFile")
   @patch.object(Popen, "communicate")
@@ -197,7 +389,8 @@ class TestBootstrap(TestCase):
                                                                       createDoneFiles_method,
                                                                       communicate_method,
                                                                       SSH_writeLogToFile_method,
-                                                                      SCP_writeLogToFile_method):
+                                                                      SCP_writeLogToFile_method,
+                                                                      get_difference_mock):
     SCP_writeLogToFile_method.return_value = None
     SSH_writeLogToFile_method.return_value = None
     communicate_method.return_value = ("", "")
@@ -208,16 +401,30 @@ class TestBootstrap(TestCase):
 
     os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
     hosts = ["hostname"]
-    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "centos6", None, "8440")
-    bootstrap.successive_hostlist = hosts
-    bootstrap.copyOsCheckScript()
-    bootstrap.successive_hostlist = hosts
-    bootstrap.copyNeededFiles()
-    bootstrap.successive_hostlist = hosts
-    bootstrap.runSetupAgent()
+    bootstrap_obj = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile",\
+                              "ambariServer", "centos6", None, "8440")
+    bootstrap_obj.successive_hostlist = hosts
+    bootstrap_obj.copyOsCheckScript()
+    bootstrap_obj.successive_hostlist = hosts
+    bootstrap_obj.copyNeededFiles()
+    bootstrap_obj.successive_hostlist = hosts
+    bootstrap_obj.runSetupAgent()
     self.assertTrue(getRunSetupWithoutPasswordCommand_method.called)
     self.assertTrue(getMoveRepoFileWithoutPasswordCommand_method.called)
+    getRunSetupWithoutPasswordCommand_method.reset()
+    getMoveRepoFileWithoutPasswordCommand_method.reset()
 
+    get_difference_mock.return_value = None
+    self.assertTrue(bootstrap_obj.copyNeededFiles() == 0)
+    self.assertTrue(getRunSetupWithoutPasswordCommand_method.called)
+    self.assertTrue(getMoveRepoFileWithoutPasswordCommand_method.called)
+    getRunSetupWithoutPasswordCommand_method.reset()
+    getMoveRepoFileWithoutPasswordCommand_method.reset()
+
+    bootstrap_obj.successive_hostlist = None
+    bootstrap_obj.copyNeededFiles()
+    self.assertTrue(getRunSetupWithoutPasswordCommand_method.called)
+    self.assertTrue(getMoveRepoFileWithoutPasswordCommand_method.called)
 
   @patch.object(BootStrap, "runSetupAgent")
   @patch.object(BootStrap, "copyNeededFiles")
@@ -323,7 +530,8 @@ class TestBootstrap(TestCase):
 
     os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
     version = "1.1.1"
-    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "centos6", version, "8440")
+    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer",\
+                          "centos6", version, "8440")
     runSetupCommand = bootstrap.getRunSetupCommand("hostname")
     self.assertTrue(runSetupCommand.endswith(version + " 8440"))
 
@@ -343,7 +551,8 @@ class TestBootstrap(TestCase):
 
     os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
     version = None
-    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "centos6", version, "8440")
+    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile",\
+                          "ambariServer", "centos6", version, "8440")
     runSetupCommand = bootstrap.getRunSetupCommand("hostname")
     self.assertTrue(runSetupCommand.endswith("8440"))
 
@@ -418,6 +627,7 @@ class TestBootstrap(TestCase):
     self.assertTrue(ret == 1)
 
 
+
   def test_PSSH_constructor_argument_validation(self):
     dummy_command = "command"
     dummy_dict = {

+ 161 - 47
ambari-server/src/test/python/TestSetupAgent.py

@@ -15,57 +15,32 @@ 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.
 '''
-
+import subprocess
+from mock.mock import MagicMock
 from unittest import TestCase
 from mock.mock import patch
-from subprocess import Popen
 import sys
 setup_agent = __import__('setupAgent')
 
 class TestSetupAgent(TestCase):
 
   @patch("sys.exit")
-  @patch.object(setup_agent, 'is_suse')
-  @patch.object(setup_agent, 'runAgent')
-  @patch.object(setup_agent, 'configureAgent')
-  @patch.object(setup_agent, 'installAgentSuse')
-  @patch.object(setup_agent, 'checkServerReachability')
-  @patch.object(setup_agent, 'checkAgentPackageAvailabilitySuse')
-  @patch.object(setup_agent, 'checkAgentPackageAvailability')
-  @patch.object(setup_agent, 'findNearestAgentPackageVersionSuse')
-  @patch.object(setup_agent, 'findNearestAgentPackageVersion')
-  def test_checkServerReachability(self, findNearestAgentPackageVersion_method,
-                                                       findNearestAgentPackageVersionSuse_method,
-                                                       checkAgentPackageAvailability_method,
-                                                       checkAgentPackageAvailabilitySuse_method,
-                                                       checkServerReachability_method,
-                                                       installAgentSuse_method,
-                                                       configureAgent_method,
-                                                       runAgent_method,
-                                                       is_suse_method,
-                                                       exit_mock):
-    
-    checkServerReachability_method.return_value = {
-
-    }
-    
-    checkAgentPackageAvailabilitySuse_method.return_value = {
-     "exitstatus" : 0
-    }
-    
-    findNearestAgentPackageVersionSuse_method.return_value = {
-     "exitstatus" : 0,
-     "log": ["1.1.1", ""]
-    }
-     
-    installAgentSuse_method.return_value = {}
-    configureAgent_method.return_value = {}
-    runAgent_method.return_value = 0
-    
-        
-    setup_agent.main(("/root/","password","1.1.1","8080"))
-    self.assertTrue(checkServerReachability_method.called)
-    pass
+  @patch("socket.socket")
+  def test_checkServerReachability(self, socket_mock, exit_mock):
+      setup_agent.checkServerReachability("localhost", 8080)
+      self.assertTrue(socket_mock.called)
+      s = socket_mock.return_value
+      s.connect = MagicMock()
+      def side_effect():
+          raise Exception(1, "socket is closed")
+      s.connect.side_effect = side_effect
+      try:
+          setup_agent.checkServerReachability("localhost", 8080)
+          self.fail("Should throw exception because port is closed")
+      except Exception:
+      # Expected
+          self.assertTrue(exit_mock.called)
+          pass
 
 
   @patch.object(setup_agent, 'execOsCommand')
@@ -85,14 +60,23 @@ class TestSetupAgent(TestCase):
     passphrase = "passphrase"
     call_mock.return_value = 0
     execOsCommand_mock.return_value = {'log': 'log', 'exitstatus': 0}
-
     # Test if expected_hostname is passed
     ret = setup_agent.runAgent(passphrase, expected_hostname)
     cmdStr = str(call_mock.call_args_list[0][0])
     self.assertTrue(expected_hostname in cmdStr)
     self.assertEqual(ret, 0)
-
-
+    # Key 'log' not found
+    execOsCommand_mock.return_value = None
+    ret = setup_agent.runAgent(passphrase, expected_hostname)
+    cmdStr = str(call_mock.call_args_list[0][0])
+    self.assertTrue(expected_hostname in cmdStr)
+    self.assertEqual(ret, 1)
+    # Retcode id not 0
+    execOsCommand_mock.return_value = {'log': 'log', 'exitstatus': 2}
+    ret = setup_agent.runAgent(passphrase, expected_hostname)
+    cmdStr = str(call_mock.call_args_list[0][0])
+    self.assertTrue(expected_hostname in cmdStr)
+    self.assertEqual(ret, 2)
 
 
   @patch.object(setup_agent, 'is_suse')
@@ -262,4 +246,134 @@ class TestSetupAgent(TestCase):
     self.assertFalse(findNearestAgentPackageVersionSuse_method.called)
     self.assertTrue(findNearestAgentPackageVersion_method.called)
     self.assertTrue(result_version == "")
-    pass
+    checkAgentPackageAvailabilitySuse_method.reset()
+    checkAgentPackageAvailability_method.reset()
+    findNearestAgentPackageVersionSuse_method.reset()
+    findNearestAgentPackageVersion_method.reset()
+
+    projectVersion = None
+    result_version = None
+
+    self.assertFalse(checkAgentPackageAvailabilitySuse_method.called)
+    self.assertTrue(checkAgentPackageAvailability_method.called)
+    self.assertFalse(findNearestAgentPackageVersionSuse_method.called)
+    self.assertTrue(findNearestAgentPackageVersion_method.called)
+    self.assertTrue(result_version == projectVersion)
+
+    pass
+
+  @patch.object(subprocess, 'Popen')
+  def test_execOsCommand(self, Popen_mock):
+    self.assertFalse(setup_agent.execOsCommand("hostname -f") == None)
+
+  @patch("os.path.isfile")
+  @patch("__builtin__.open")
+  def test_is_suse(self, open_mock, isfile_mock):
+    self.assertFalse(setup_agent.is_suse())
+    isfile_mock.return_value = True
+    f = open_mock.return_value
+    f.read.return_value = " suse "
+    self.assertTrue(setup_agent.is_suse())
+
+  @patch.object(subprocess, 'Popen')
+  def test_installAgentSuse(self, Popen_mock):
+    self.assertFalse(setup_agent.installAgentSuse("1") == None)
+
+  @patch.object(setup_agent, 'execOsCommand')
+  def test_installPreReq(self, execOsCommand_mock):
+    execOsCommand_mock.side_effect = [{"log": " epel "}, "hostname -f", {"log": " something "}, "hostname -f"]
+    setup_agent.installPreReq()
+    setup_agent.installPreReq()
+    self.assertTrue(execOsCommand_mock.call_count == 4)
+
+
+  @patch.object(setup_agent, 'runAgent')
+  @patch.object(setup_agent, 'configureAgent')
+  @patch.object(setup_agent, 'installAgent')
+  @patch.object(setup_agent, 'installPreReq')
+  @patch.object(setup_agent, 'installAgentSuse')
+  @patch.object(setup_agent, 'is_suse')
+  @patch.object(setup_agent, 'getOptimalVersion')
+  @patch.object(setup_agent, 'checkServerReachability')
+  @patch("sys.exit")
+  @patch("os.path.dirname")
+  @patch("os.path.realpath")
+  def test_setup_agent_main(self, dirname_mock, realpath_mock, exit_mock, checkServerReachability_mock,
+                            getOptimalVersion_mock, is_suse_mock, installAgentSuse_mock, installPreReq_mock,
+                            installAgent_mock, configureAgent_mock, runAgent_mock):
+    installPreReq_mock.return_value = {'log': 'log', 'exitstatus': 0}
+    installAgent_mock.return_value = {'log': 'log', 'exitstatus': 0}
+    installAgentSuse_mock.return_value = {'log': 'log', 'exitstatus': 0}
+    runAgent_mock.return_value = 0
+    setup_agent.main(("setupAgent.py","agents_host","password", "server_hostname","1.1.1","8080"))
+    self.assertTrue(exit_mock.called)
+    exit_mock.reset()
+    setup_agent.main(("setupAgent.py","agents_host","password", "server_hostname","null","8080"))
+    self.assertTrue(exit_mock.called)
+    exit_mock.reset()
+    is_suse_mock.return_value = False
+    setup_agent.main(("setupAgent.py","agents_host","password", "server_hostname","null","null"))
+    self.assertTrue(exit_mock.called)
+    exit_mock.reset()
+    def side_effect(retcode):
+      raise Exception(retcode, "sys.exit")
+    exit_mock.side_effect = side_effect
+    #BUG-6769 Bootstrap does not fail on yum error
+    #if "yum -y install epel-release" return not 0 result
+    installPreReq_mock.return_value = {'log': 'log', 'exitstatus': 1}
+    try:
+        setup_agent.main(("setupAgent.py","agents_host","password", "server_hostname","1.1.1","8080"))
+        self.fail("Should throw exception")
+    except Exception:
+        # Expected
+        pass
+    self.assertTrue(exit_mock.called)
+    exit_mock.reset()
+    #if "yum -y install --nogpgcheck ambari-agent" return not 0 result
+    installPreReq_mock.return_value = {'log': 'log', 'exitstatus': 0}
+    installAgent_mock.return_value = {'log': 'log', 'exitstatus': 1}
+    try:
+        setup_agent.main(("setupAgent.py","agents_host","password", "server_hostname","1.1.1","8080"))
+        self.fail("Should throw exception")
+    except Exception:
+        # Expected
+        pass
+    self.assertTrue(exit_mock.called)
+    exit_mock.reset()
+    #if suse
+    is_suse_mock.return_value = True
+    #if "zypper install -y ambari-agent" return not 0 result
+    installAgentSuse_mock.return_value = {'log': 'log', 'exitstatus': 1}
+    try:
+        setup_agent.main(("setupAgent.py","agents_host","password", "server_hostname","1.1.1","8080"))
+        self.fail("Should throw exception")
+    except Exception:
+        # Expected
+        pass
+    self.assertTrue(exit_mock.called)
+
+
+  @patch.object(setup_agent, 'execOsCommand')
+  def test_checkAgentPackageAvailabilitySuse(self, execOsCommand_mock):
+    setup_agent.checkAgentPackageAvailabilitySuse("1.1.1")
+    self.assertTrue(execOsCommand_mock.called)
+
+  @patch.object(setup_agent, 'execOsCommand')
+  def test_checkAgentPackageAvailability(self, execOsCommand_mock):
+      setup_agent.checkAgentPackageAvailability("1.1.1")
+      self.assertTrue(execOsCommand_mock.called)
+
+  @patch.object(setup_agent, 'execOsCommand')
+  def test_findNearestAgentPackageVersionSuse(self, execOsCommand_mock):
+      setup_agent.findNearestAgentPackageVersionSuse("1.1.1")
+      self.assertTrue(execOsCommand_mock.called)
+
+  @patch.object(setup_agent, 'execOsCommand')
+  def test_findNearestAgentPackageVersion(self, execOsCommand_mock):
+      setup_agent.findNearestAgentPackageVersion("1.1.1")
+      self.assertTrue(execOsCommand_mock.called)
+
+  @patch.object(setup_agent, 'execOsCommand')
+  def test_installAgent(self, execOsCommand_mock):
+    setup_agent.installAgent("1.1.1")
+    self.assertTrue(execOsCommand_mock.called)