Author: swagle
Date: Thu May 16 17:05:24 2013
New Revision: 1483449

URL: http://svn.apache.org/r1483449
Log:
AMBARI-2140. Improve Ambari-agent test coverage. Missing files. (swagle)

Added:
    incubator/ambari/trunk/ambari-agent/src/test/python/TestMain.py
    incubator/ambari/trunk/ambari-agent/src/test/python/TestSecurity.py

Added: incubator/ambari/trunk/ambari-agent/src/test/python/TestMain.py
URL: 
http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-agent/src/test/python/TestMain.py?rev=1483449&view=auto
==============================================================================
--- incubator/ambari/trunk/ambari-agent/src/test/python/TestMain.py (added)
+++ incubator/ambari/trunk/ambari-agent/src/test/python/TestMain.py Thu May 16 
17:05:24 2013
@@ -0,0 +1,247 @@
+#!/usr/bin/env python2.6
+
+'''
+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.
+'''
+import StringIO
+import sys
+
+from ambari_agent import NetUtil, security
+from mock.mock import MagicMock, patch, ANY
+import unittest
+from ambari_agent import ProcessHelper, main
+from ambari_agent import ProcessHelper, main
+import logging
+import signal
+from ambari_agent.AmbariConfig import AmbariConfig
+import ConfigParser
+import os
+import tempfile
+from ambari_agent.Controller import Controller
+
+
+class TestMain(unittest.TestCase):
+
+  def setUp(self):
+    # disable stdout
+    out = StringIO.StringIO()
+    sys.stdout = out
+
+
+  def tearDown(self):
+    # enable stdout
+    sys.stdout = sys.__stdout__
+
+
+  @patch("os._exit")
+  @patch("os.getpid")
+  @patch.object(ProcessHelper, "stopAgent")
+  def test_signal_handler(self, stopAgent_mock, os_getpid_mock, os_exit_mock):
+    # testing exit of children
+    main.agentPid = 4444
+    os_getpid_mock.return_value = 5555
+    main.signal_handler("signum", "frame")
+    self.assertTrue(os_exit_mock.called)
+
+    os_exit_mock.reset_mock()
+
+    # testing exit of main process
+    os_getpid_mock.return_value = main.agentPid
+    main.signal_handler("signum", "frame")
+    self.assertFalse(os_exit_mock.called)
+    self.assertTrue(stopAgent_mock.called)
+
+
+  @patch.object(main.logger, "addHandler")
+  @patch.object(main.logger, "setLevel")
+  @patch("logging.handlers.RotatingFileHandler")
+  def test_setup_logging(self, rfh_mock, setLevel_mock, addHandler_mock):
+    # Testing silent mode
+    main.setup_logging(False)
+    self.assertTrue(addHandler_mock.called)
+    setLevel_mock.assert_called_with(logging.INFO)
+
+    addHandler_mock.reset_mock()
+    setLevel_mock.reset_mock()
+
+    # Testing verbose mode
+    main.setup_logging(True)
+    self.assertTrue(addHandler_mock.called)
+    setLevel_mock.assert_called_with(logging.DEBUG)
+
+
+  @patch.object(main.logger, "setLevel")
+  @patch("logging.basicConfig")
+  def test_update_log_level(self, basicConfig_mock, setLevel_mock):
+    config = AmbariConfig().getConfig()
+
+    # Testing with default setup (config file does not contain loglevel entry)
+    # Log level should not be changed
+    main.update_log_level(config)
+    self.assertFalse(setLevel_mock.called)
+
+    setLevel_mock.reset_mock()
+
+    # Testing debug mode
+    config.set('agent', 'loglevel', 'DEBUG')
+    main.update_log_level(config)
+    setLevel_mock.assert_called_with(logging.DEBUG)
+    setLevel_mock.reset_mock()
+
+    # Testing any other mode
+    config.set('agent', 'loglevel', 'INFO')
+    main.update_log_level(config)
+    setLevel_mock.assert_called_with(logging.INFO)
+
+    setLevel_mock.reset_mock()
+
+    config.set('agent', 'loglevel', 'WRONG')
+    main.update_log_level(config)
+    setLevel_mock.assert_called_with(logging.INFO)
+
+
+  @patch("signal.signal")
+  def test_bind_signal_handlers(self, signal_mock):
+    main.bind_signal_handlers()
+    # Check if on SIGINT/SIGTERM agent is configured to terminate
+    signal_mock.assert_any_call(signal.SIGINT, main.signal_handler)
+    signal_mock.assert_any_call(signal.SIGTERM, main.signal_handler)
+    # Check if on SIGUSR1 agent is configured to fall into debug
+    signal_mock.assert_any_call(signal.SIGUSR1, main.debug)
+
+
+  @patch("os.path.exists")
+  @patch("ConfigParser.RawConfigParser.read")
+  def test_resolve_ambari_config(self, read_mock, exists_mock):
+    # Trying case if conf file exists
+    exists_mock.return_value = True
+    main.resolve_ambari_config()
+    self.assertTrue(read_mock.called)
+
+    exists_mock.reset_mock()
+    read_mock.reset_mock()
+
+    # Trying case if conf file does not exist
+    exists_mock.return_value = False
+    main.resolve_ambari_config()
+    self.assertFalse(read_mock.called)
+
+
+  @patch("sys.exit")
+  @patch("os.path.isfile")
+  @patch("os.path.isdir")
+  def test_perform_prestart_checks(self, isdir_mock, isfile_mock, exit_mock):
+    main.config = AmbariConfig().getConfig()
+    # Trying case if there is another instance running
+    isfile_mock.return_value = True
+    isdir_mock.return_value = True
+    main.perform_prestart_checks()
+    self.assertTrue(exit_mock.called)
+
+    isfile_mock.reset_mock()
+    isdir_mock.reset_mock()
+    exit_mock.reset_mock()
+
+    # Trying case if agent prefix dir does not exist
+    isfile_mock.return_value = False
+    isdir_mock.return_value = False
+    main.perform_prestart_checks()
+    self.assertTrue(exit_mock.called)
+
+    isfile_mock.reset_mock()
+    isdir_mock.reset_mock()
+    exit_mock.reset_mock()
+
+    # Trying normal case
+    isfile_mock.return_value = False
+    isdir_mock.return_value = True
+    main.perform_prestart_checks()
+    self.assertFalse(exit_mock.called)
+
+
+  @patch("time.sleep")
+  @patch("os.kill")
+  @patch("os._exit")
+  @patch("os.path.exists")
+  def test_daemonize_and_stop(self, exists_mock, _exit_mock, kill_mock, 
sleep_mock):
+    oldpid = ProcessHelper.pidfile
+    pid = str(os.getpid())
+    _, tmpoutfile = tempfile.mkstemp()
+    ProcessHelper.pidfile = tmpoutfile
+
+    # Test daemonization
+    main.daemonize()
+    saved = open(ProcessHelper.pidfile, 'r').read()
+    self.assertEqual(pid, saved)
+
+    # Reuse pid file when testing agent stop
+    # Testing normal exit
+    exists_mock.return_value = False
+    main.stop_agent()
+    kill_mock.assert_called_with(int(pid), signal.SIGTERM)
+    _exit_mock.assert_called_with(0)
+
+    # Restore
+    kill_mock.reset_mock()
+    _exit_mock.reset_mock()
+
+    # Testing exit when failed to remove pid file
+    exists_mock.return_value = True
+    main.stop_agent()
+    kill_mock.assert_any_call(int(pid), signal.SIGTERM)
+    kill_mock.assert_any_call(int(pid), signal.SIGKILL)
+    _exit_mock.assert_called_with(1)
+
+    # Restore
+    ProcessHelper.pidfile = oldpid
+    os.remove(tmpoutfile)
+
+
+  @patch.object(main, "setup_logging")
+  @patch.object(main, "bind_signal_handlers")
+  @patch.object(main, "stop_agent")
+  @patch.object(main, "resolve_ambari_config")
+  @patch.object(main, "perform_prestart_checks")
+  @patch.object(main, "daemonize")
+  @patch.object(main, "killstaleprocesses")
+  @patch.object(main, "update_log_level")
+  @patch.object(NetUtil.NetUtil, "try_to_connect")
+  @patch.object(security.CertificateManager, "__init__")
+  @patch.object(security.CertificateManager, "initSecurity")
+  @patch.object(Controller, "__init__")
+  @patch.object(Controller, "start")
+  def test_main(self, start_mock, Controller_init_mock , initSecurity_mock,
+                CertificateManager_init_mock, try_to_connect_mock, 
update_log_level_mock,
+                killstaleprocesses_mock, daemonize_mock, 
perform_prestart_checks_mock,
+                resolve_ambari_config_mock, stop_mock, 
bind_signal_handlers_mock, setup_logging_mock):
+    CertificateManager_init_mock.return_value = None
+    Controller_init_mock.return_value = None
+
+    #testing call without command-line arguments
+    main.main()
+
+    self.assertTrue(setup_logging_mock.called)
+    self.assertTrue(bind_signal_handlers_mock.called)
+    self.assertFalse(stop_mock.called)
+    self.assertTrue(resolve_ambari_config_mock.called)
+    self.assertTrue(perform_prestart_checks_mock.called)
+    self.assertTrue(daemonize_mock.called)
+    self.assertTrue(killstaleprocesses_mock.called)
+    self.assertTrue(update_log_level_mock.called)
+    try_to_connect_mock.assert_called_once_with(ANY, -1, ANY)
+    self.assertTrue(initSecurity_mock.called)
+    self.assertTrue(start_mock.called)

Added: incubator/ambari/trunk/ambari-agent/src/test/python/TestSecurity.py
URL: 
http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-agent/src/test/python/TestSecurity.py?rev=1483449&view=auto
==============================================================================
--- incubator/ambari/trunk/ambari-agent/src/test/python/TestSecurity.py (added)
+++ incubator/ambari/trunk/ambari-agent/src/test/python/TestSecurity.py Thu May 
16 17:05:24 2013
@@ -0,0 +1,305 @@
+#!/usr/bin/env python2.6
+
+'''
+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.
+'''
+import StringIO
+import sys, subprocess
+
+from ambari_agent import NetUtil
+from ambari_agent.security import CertificateManager
+from mock.mock import MagicMock, patch, ANY
+import mock.mock
+import unittest
+from ambari_agent import ProcessHelper, main
+import logging
+import signal
+from ambari_agent.AmbariConfig import AmbariConfig
+import ConfigParser
+import os
+import tempfile
+from ambari_agent.Controller import Controller
+from ambari_agent import security
+
+aa = mock.mock.mock_open()
+class TestSecurity(unittest.TestCase):
+
+  def setUp(self):
+    # disable stdout
+    out = StringIO.StringIO()
+    sys.stdout = out
+    # Create config
+    self.config = AmbariConfig().getConfig()
+    # Instantiate CachedHTTPSConnection (skip connect() call)
+    with patch.object(security.VerifiedHTTPSConnection, "connect"):
+      self.cachedHTTPSConnection = security.CachedHTTPSConnection(self.config)
+
+
+  def tearDown(self):
+    # enable stdout
+    sys.stdout = sys.__stdout__
+
+
+  ### VerifiedHTTPSConnection ###
+
+  @patch("socket.create_connection")
+  @patch("ssl.wrap_socket")
+  def test_VerifiedHTTPSConnection_connect(self, wrap_socket_mock, 
create_connection_mock):
+    self.config.set('security', 'keysdir', '/dummy-keysdir')
+    connection = security.VerifiedHTTPSConnection("example.com")
+    connection._tunnel_host = False
+    connection.sock = None
+    connection.connect()
+    self.assertTrue(wrap_socket_mock.called)
+
+
+  ### CachedHTTPSConnection ###
+
+  @patch.object(security.VerifiedHTTPSConnection, "connect")
+  def test_CachedHTTPSConnection_connect(self, vhc_connect_mock):
+    self.config.set('server', 'hostname', 'dummy.server.hostname')
+    self.config.set('server', 'secured_url_port', '443')
+    # Testing not connected case
+    self.cachedHTTPSConnection.connected = False
+    self.cachedHTTPSConnection.connect()
+    self.assertTrue(vhc_connect_mock.called)
+    vhc_connect_mock.reset_mock()
+    # Testing already connected case
+    self.cachedHTTPSConnection.connect()
+    self.assertFalse(vhc_connect_mock.called)
+
+
+  @patch.object(security.CachedHTTPSConnection, "connect")
+  def test_forceClear(self, connect_mock):
+    # Testing if httpsconn instance changed
+    old = self.cachedHTTPSConnection.httpsconn
+    self.cachedHTTPSConnection.forceClear()
+    self.assertNotEqual(old, self.cachedHTTPSConnection.httpsconn)
+
+
+  @patch.object(security.CachedHTTPSConnection, "connect")
+  def test_request(self, connect_mock):
+    httpsconn_mock = MagicMock(create = True)
+    self.cachedHTTPSConnection.httpsconn = httpsconn_mock
+
+    dummy_request = MagicMock(create = True)
+    dummy_request.get_method.return_value = "dummy_get_method"
+    dummy_request.get_full_url.return_value = "dummy_full_url"
+    dummy_request.get_data.return_value = "dummy_get_data"
+    dummy_request.headers = "dummy_headers"
+
+    responce_mock = MagicMock(create = True)
+    responce_mock.read.return_value = "dummy responce"
+    httpsconn_mock.getresponse.return_value = responce_mock
+
+    # Testing normal case
+    responce = self.cachedHTTPSConnection.request(dummy_request)
+
+    self.assertEqual(responce, responce_mock.read.return_value)
+    httpsconn_mock.request.assert_called_once_with(
+      dummy_request.get_method.return_value,
+      dummy_request.get_full_url.return_value,
+      dummy_request.get_data.return_value,
+      dummy_request.headers)
+
+    # Testing case of exception
+    try:
+      def side_eff():
+        raise Exception("Dummy exception")
+      httpsconn_mock.read.side_effect = side_eff
+      responce = self.cachedHTTPSConnection.request(dummy_request)
+      self.fail("Should raise IOError")
+    except Exception, err:
+      # Expected
+      pass
+
+
+  ### CertificateManager ###
+
+
+  @patch("ambari_agent.hostname.hostname")
+  def test_getAgentKeyName(self, hostname_mock):
+    hostname_mock.return_value = "dummy.hostname"
+    self.config.set('security', 'keysdir', '/dummy-keysdir')
+    man = CertificateManager(self.config)
+    res = man.getAgentKeyName()
+    self.assertEquals(res, "/dummy-keysdir/dummy.hostname.key")
+
+
+  @patch("ambari_agent.hostname.hostname")
+  def test_getAgentCrtName(self, hostname_mock):
+    hostname_mock.return_value = "dummy.hostname"
+    self.config.set('security', 'keysdir', '/dummy-keysdir')
+    man = CertificateManager(self.config)
+    res = man.getAgentCrtName()
+    self.assertEquals(res, "/dummy-keysdir/dummy.hostname.crt")
+
+
+  @patch("ambari_agent.hostname.hostname")
+  def test_getAgentCrtReqName(self, hostname_mock):
+    hostname_mock.return_value = "dummy.hostname"
+    self.config.set('security', 'keysdir', '/dummy-keysdir')
+    man = CertificateManager(self.config)
+    res = man.getAgentCrtReqName()
+    self.assertEquals(res, "/dummy-keysdir/dummy.hostname.csr")
+
+
+  def test_getSrvrCrtName(self):
+    self.config.set('security', 'keysdir', '/dummy-keysdir')
+    man = CertificateManager(self.config)
+    res = man.getSrvrCrtName()
+    self.assertEquals(res, "/dummy-keysdir/ca.crt")
+
+
+  @patch("os.path.exists")
+  @patch.object(security.CertificateManager, "loadSrvrCrt")
+  @patch.object(security.CertificateManager, "getAgentKeyName")
+  @patch.object(security.CertificateManager, "genAgentCrtReq")
+  @patch.object(security.CertificateManager, "getAgentCrtName")
+  @patch.object(security.CertificateManager, "reqSignCrt")
+  def test_checkCertExists(self, reqSignCrt_mock, getAgentCrtName_mock,
+                           genAgentCrtReq_mock, getAgentKeyName_mock,
+                           loadSrvrCrt_mock, exists_mock):
+    self.config.set('security', 'keysdir', '/dummy-keysdir')
+    getAgentKeyName_mock.return_value = "dummy AgentKeyName"
+    getAgentCrtName_mock.return_value = "dummy AgentCrtName"
+    man = CertificateManager(self.config)
+
+    # Case when all files exist
+    exists_mock.side_effect = [True, True, True]
+    man.checkCertExists()
+    self.assertFalse(loadSrvrCrt_mock.called)
+    self.assertFalse(genAgentCrtReq_mock.called)
+    self.assertFalse(reqSignCrt_mock.called)
+
+    # Absent server cert
+    exists_mock.side_effect = [False, True, True]
+    man.checkCertExists()
+    self.assertTrue(loadSrvrCrt_mock.called)
+    self.assertFalse(genAgentCrtReq_mock.called)
+    self.assertFalse(reqSignCrt_mock.called)
+    loadSrvrCrt_mock.reset_mock()
+
+    # Absent agent key
+    exists_mock.side_effect = [True, False, True]
+    man.checkCertExists()
+    self.assertFalse(loadSrvrCrt_mock.called)
+    self.assertTrue(genAgentCrtReq_mock.called)
+    self.assertFalse(reqSignCrt_mock.called)
+    genAgentCrtReq_mock.reset_mock()
+
+    # Absent agent cert
+    exists_mock.side_effect = [True, True, False]
+    man.checkCertExists()
+    self.assertFalse(loadSrvrCrt_mock.called)
+    self.assertFalse(genAgentCrtReq_mock.called)
+    self.assertTrue(reqSignCrt_mock.called)
+    reqSignCrt_mock.reset_mock()
+
+
+
+  @patch('urllib2.urlopen')
+  @patch.object(security.CertificateManager, "getSrvrCrtName")
+  def test_loadSrvrCrt(self, getSrvrCrtName_mock, urlopen_mock):
+    read_mock = MagicMock(create=True)
+    read_mock.read.return_value = "dummy_cert"
+    urlopen_mock.return_value = read_mock
+    _, tmpoutfile = tempfile.mkstemp()
+    getSrvrCrtName_mock.return_value = tmpoutfile
+
+    man = CertificateManager(self.config)
+    man.loadSrvrCrt()
+
+    # Checking file contents
+    saved = open(tmpoutfile, 'r').read()
+    self.assertEqual(saved, read_mock.read.return_value)
+
+    os.unlink(tmpoutfile)
+
+
+  @patch("ambari_agent.hostname.hostname")
+  @patch('__builtin__.open', create=True, autospec=True)
+  @patch.dict('os.environ', {'DUMMY_PASSPHRASE': 'dummy-passphrase'})
+  @patch('json.dumps')
+  @patch('urllib2.Request')
+  @patch('urllib2.urlopen')
+  @patch('json.loads')
+  def test_reqSignCrt(self, loads_mock, urlopen_mock, request_mock, 
dumps_mock, open_mock, hostname_mock):
+    self.config.set('security', 'keysdir', '/dummy-keysdir')
+    self.config.set('security', 'passphrase_env_var_name', 'DUMMY_PASSPHRASE')
+    man = CertificateManager(self.config)
+    hostname_mock.return_value = "dummy-hostname"
+
+    open_mock.return_value.read.return_value = "dummy_request"
+    urlopen_mock.return_value.read.return_value = "dummy_server_request"
+    loads_mock.return_value = {
+      'result': 'OK',
+      'signedCa': 'dummy-crt'
+    }
+
+    # Test normal server interaction
+    man.reqSignCrt()
+
+    self.assertEqual(dumps_mock.call_args[0][0], {
+      'csr'       : 'dummy_request',
+      'passphrase' : 'dummy-passphrase'
+    })
+    self.assertEqual(open_mock.return_value.write.call_args[0][0], 'dummy-crt')
+
+    # Test negative server reply
+    dumps_mock.reset_mock()
+    open_mock.return_value.write.reset_mock()
+    loads_mock.return_value = {
+      'result': 'FAIL',
+      'signedCa': 'fail-crt'
+    }
+
+    man.reqSignCrt()
+    self.assertFalse(open_mock.return_value.write.called)
+
+    # Test connection fail
+    dumps_mock.reset_mock()
+    open_mock.return_value.write.reset_mock()
+
+    try:
+      man.reqSignCrt()
+      self.fail("Expected exception here")
+    except Exception, err:
+      # expected
+      pass
+
+
+
+
+  @patch("subprocess.Popen")
+  @patch("subprocess.Popen.communicate")
+  def test_genAgentCrtReq(self, communicate_mock, popen_mock):
+    man = CertificateManager(self.config)
+    p = MagicMock(spec=subprocess.Popen)
+    p.communicate = communicate_mock
+    popen_mock.return_value = p
+    man.genAgentCrtReq()
+    self.assertTrue(popen_mock.called)
+    self.assertTrue(communicate_mock.called)
+
+
+  @patch.object(security.CertificateManager, "checkCertExists")
+  def test_initSecurity(self, checkCertExists_method):
+    man = CertificateManager(self.config)
+    man.initSecurity()
+    self.assertTrue(checkCertExists_method.called)
+


Reply via email to