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)
+