polardbxengine/storage/ndb/mcc/tst/tst_main.py

369 lines
13 KiB
Python

# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2.0,
# as published by the Free Software Foundation.
#
# This program is also distributed with certain software (including
# but not limited to OpenSSL) that is licensed under separate terms,
# as designated in a particular file or component or in included license
# documentation. The authors of MySQL hereby grant you an additional
# permission to link the program and your derivative works with the
# separately licensed software that they have included with MySQL.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License, version 2.0, for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#!/bin/env python
import platform
(pymajor, pyminor, pypatch) = map(int, platform.python_version_tuple())
assert pymajor == 2
import sys
import os
import os.path
tst_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
mcc_dir = os.path.dirname(tst_dir)
# Paramiko from Bazaar
sys.path += [tst_dir, mcc_dir, '/opt/csw/lib/python/site-packages' ]
import logging
if pyminor < 7:
print('Running with Python version %s',
str(platform.python_version_tuple()))
import unittest2 as unittest
else:
import unittest
utmod = unittest
import traceback
import json
import urlparse
import time
import socket
import stat
import tempfile
import platform
import time
import contextlib
import request_handler
import config_parser
import util
from util import mock_msg, is_set
from clusterhost import ABClusterHost, LocalClusterHost, produce_ABClusterHost
from remote_clusterhost import RemoteClusterHost
from paramiko import SSHClient, WarningPolicy
_ndb_config = os.path.join('..', '..', '..', 'bin', 'ndb_config')
def tst_tempify(*fs):
td = util.get_val(os.environ, 'MYSQL_TMP_DIR', tempfile.gettempdir())
#td = tempfile.mkdtemp()
return os.path.join(td, *fs)
def defdatadir():
return os.path.join(os.path.expanduser('~'), 'MySQL_Cluster', 'data')
# Default tst configuration. Can be overridden in config.json
_cfg = { 'debuglevel': 'DEBUG' }
def cfg():
return _cfg
request_handler.configdir = '..'
def_datadir = os.path.join(os.path.expanduser('~'), 'MySQL_Cluster', 'data')
def mock_ABClusterHost(hle):
return produce_ABClusterHost(hostname=hle['hostInfoRep']['host']['name'], user=util.get_val(hle, 'username'), pwd=util.get_val(hle, 'password'))
def local_ipv4_ssh_addr():
for (family, socktype, proto, canonname, sockaddr) in socket.getaddrinfo(socket.gethostname(), 22):
if family == socket.AF_INET:
return sockaddr[0]
def host_is_unreachable(hostname, port=22):
rd = util._retdict('ECONNREFUSED', True)
rd[socket.EAI_NONAME] = True
return util.try_connect(hostname, port, False, rd)
def is_local_sshd_available():
with contextlib.closing(SSHClient()) as c:
c.set_missing_host_key_policy(WarningPolicy())
#c.load_system_host_keys()
try:
c.connect(local_ipv4_ssh_addr(), password=util.get_val(os.environ, 'SSH_PWD'))
except:
logging.exception('No usable sshd on this machine: ')
return False
else:
return True
def mock_msg_as_json(cmd, body):
return json.dumps(mock_msg(cmd,body))
def json_normalize(x):
return json.loads(json.dumps(x))
class Test00Utils(utmod.TestCase):
def test_version_tuple(self):
print [ int(filter(str.isdigit, vn)) for vn in ('2', '7', '2+')]
def test_Param(self):
print util.Param({'name':'--c', 'val':'bar', 'sep':'@'})
x = util.Param('--a')
print json.dumps(x)
print util.Param('--b','foo')
print util.Param('--d','baz','#')
def test_host_is_unreachable(self):
self.assertTrue(host_is_unreachable('some_non_existent_host_name'))
@utmod.skipIf(not is_local_sshd_available(), 'FIXME: Sshd is not running by default on Windows - test some other port?')
def test_host_is_unreachable(self):
self.assertFalse(host_is_unreachable(local_ipv4_ssh_addr()))
def test_to_json(self):
obj = [ "sleep" "300" ]
json_string = json.dumps(obj)
jobj = json.loads(json_string)
self.assertEqual(obj, jobj)
class Test0ConfigIni(utmod.TestCase):
def setUp(self):
self.ini = os.path.join(tst_dir, 'example_config.ini')
self.cp = config_parser.parse_config_ini(self.ini)
def tearDown(self):
pass
def test_get_option_values(self):
self.assertEqual(config_parser.get_option_value_set(self.cp, 'HostName'), set(['siv27','siv28']))
def test_get_node_dicts(self):
print config_parser.get_node_dicts(self.cp, 0)
def test_get_configvalues(self):
print config_parser.get_configvalues(self.cp)
print config_parser.get_processes(self.cp)
def test_parse(self):
logging.debug('ex_ini as json:\n'+json.dumps(config_parser.parse_cluster_config_ini(self.ini)))
def test_parsex(self):
logging.debug('ex_ini as json:\n'+str(config_parser.parse_cluster_config_ini_x(self.ini)))
def test_write(self):
logging.debug('ex_ini write back:\n'+config_parser.write_cluster_config_ini(config_parser.parse_cluster_config_ini(self.ini)))
@utmod.skip('Need a way to specify the cluster installdir (default cluster we are part of?')
def test_ndb_config(self):
print 'ndb config as json: ', json.dumps(util.xml_to_python(self.cluster.ndb_config_xml()))
@utmod.skipIf(not is_local_sshd_available(), 'FIXME: Sshd is not running by default on Windows - test some other port?')
class Test3Ports(utmod.TestCase):
def testPortNotAvailable(self):
self.assertFalse(util.is_port_available(local_ipv4_ssh_addr(), 22))
def testPortAvailable(self):
self.assertTrue(util.is_port_available(local_ipv4_ssh_addr(), 23))
def testFindPort(self):
self.assertEqual(util.first_available_port(local_ipv4_ssh_addr(), 22, 23), 23)
def testNotFindPort(self):
self.assertRaises(util.NoPortAvailableException,
util.first_available_port, local_ipv4_ssh_addr(), 22, 22)
class _TestABClusterHost:
def setUp(self):
self.rtd = time.strftime("%Y-%m-%dT%H-%M-%S",time.localtime())+str(self.__class__.__name__)
logging.debug('rtd: '+self.rtd)
self.ch.mkdir_p(self.rtd)
def tearDown(self):
if sys.exc_info() == (None, None, None):
logging.debug('tearDown: success')
self.ch.rm_r(self.rtd)
else:
logging.debug('tearDown: failure')
logging.exception('try this...')
self.ch.drop()
@utmod.skip('FIXME: Need the path to a program that will always be available')
def test_fg_exec(self):
self.assertTrue('This program will retrieve config options for a ndb cluster' in self.ch.exec_blocking([_ndb_config, '--help']))
def test_fileops(self):
d = self.ch.path_module.join(self.rtd, 'foo', 'bar', '')
logging.debug('d='+d)
self.ch.mkdir_p(d)
bazname = self.ch.path_module.join(d, 'baz')
with self.ch.open(bazname, 'w+') as f:
f.write('Some text here...\n')
with self.ch.open(bazname) as f:
self.assertEqual(f.read(), 'Some text here...\n')
def test_stat_dir_2(self):
if not hasattr(self.ch, 'sftp'):
return
self.assertTrue(stat.S_ISDIR(self.ch.sftp.stat(self.rtd).st_mode))
@utmod.skip('Cannot create files with attributes')
def test_list_dir_no_x(self):
nox_name = self.ch.path_module.join(self.rtd, 'nox')
notmine_name = self.ch.path_module.join(self.rtd, 'not_mine')
nox_mode = self.self.ch.sftp.stat(nox_name).st_mode
notmine_mode = self.self.ch.sftp.stat(notmine_name).st_mode
self.assertTrue(stat.S_ISDIR(nox_mode))
self.assertTrue(is_set(stat.S_IMODE(nox_mode), stat.S_IXGRP))
self.assertTrue(stat.S_ISDIR(notmine_mode))
self.assertTrue(is_set(stat.S_IMODE(notmine_mode), stat.S_IXOTH))
logging.debug('listdir(nox)='+str(self.self.ch.list_dir(nox_name)))
logging.debug('listdir(notmine)='+str(self.self.ch.list_dir(notmine_name)))
def test_mkdir_p(self):
somedir_name = self.ch.path_module.join(self.rtd, 'some_dir')
logging.debug('somedir_name'+somedir_name)
self.ch.mkdir_p(somedir_name)
def test_hostInfo(self):
self.assertGreater(self.ch.hostInfo.ram, 1000)
self.assertGreater(self.ch.hostInfo.cores, 0)
self.assertIsNotNone(self.ch.hostInfo.homedir)
class Test4LocalClusterHost(utmod.TestCase, _TestABClusterHost):
def setUp(self):
self.ch = LocalClusterHost('localhost')
_TestABClusterHost.setUp(self)
def tearDown(self):
_TestABClusterHost.tearDown(self)
@utmod.skipIf(not is_local_sshd_available(), 'No suitable local sshd')
class Test5RemoteClusterHost(utmod.TestCase, _TestABClusterHost):
def setUp(self):
self.ch = RemoteClusterHost(local_ipv4_ssh_addr(), password=util.get_val(os.environ, 'SSH_PWD'))
_TestABClusterHost.setUp(self)
def tearDown(self):
_TestABClusterHost.tearDown(self)
def test_copy_file(self):
if not hasattr(self.ch, 'sftp'):
return
content = 'Some text here\nSome more text on another line\n'
(lh, lname) = tempfile.mkstemp()
logging.debug('lname: '+lname)
try:
os.write(lh, content)
# Note! Might not work with a genuine remote host, as rex.name
# might not be creatable there
(rh, rname) = tempfile.mkstemp()
os.close(rh)
# Fixme! Assumes SFTP home is C: (More commonly HOMEPATH or USERPROFILE?
rname = os.path.basename(rname)
self.ch.sftp.put(lname, rname)
try:
(llh, llname) = tempfile.mkstemp()
os.close(llh)
self.ch.sftp.get(rname, llname)
try:
with open(llname) as llh:
self.assertEqual(content, llh.read())
finally:
os.remove(llname)
finally:
self.ch.sftp.remove(rname)
finally:
os.close(lh)
os.remove(lname)
def test_mkdir(self):
if not hasattr(self.ch, 'sftp'):
return
(h, n) = tempfile.mkstemp()
os.write(h, "Some text here\nSome more text on another line\n")
os.close(h)
some_new_dir_name = self.ch.path_module.join(self.rtd, 'some_new_dir')
self.ch.sftp.mkdir(some_new_dir_name)
tmpex_name = self.ch.path_module.join(some_new_dir_name, 'example.txt')
self.ch.sftp.put(n, tmpex_name)
os.remove(n)
def test_stat_dir(self):
if not hasattr(self.ch, 'sftp'):
return
self.assertEqual(stat.S_IFMT(self.ch.sftp.stat(self.rtd).st_mode), stat.S_IFDIR)
class Test6RequestHandler(utmod.TestCase):
def setUp(self):
self.ssh = {'user': None, 'pwd': None }
def tearDown(self):
pass
def test_hostInfoReq(self):
json_str = mock_msg_as_json('hostInfoReq', {'ssh': self.ssh,
'hostName': 'localhost'})
print 'hostInfoReq: '+json_str
print request_handler.handle_req(json.loads(json_str))
def test_createFileReq(self):
json_str = mock_msg_as_json('createFileReq',
{'ssh': self.ssh, 'file': {'hostName': 'localhost', 'path': tempfile.gettempdir(), 'name': 'foobar'},
'contentString': 'a=0\nb=1\n', 'contents': {'params': {'sep': None, 'para': [{'name': None, 'sep': None, 'val': None}]}}})
print json_str
try:
print request_handler.handle_req(json.loads(json_str))
finally:
try:
os.remove(os.path.join(tempfile.gettempdir(),'foobar'))
except:
pass
if __name__ == '__main__':
if cfg()['debuglevel'] is not None:
import logging
fmt = '%(asctime)s: %(levelname)s [%(funcName)s;%(filename)s:%(lineno)d]: %(message)s '
logging.basicConfig(level=getattr(logging, cfg()['debuglevel']), format=fmt)
try:
import xmlrunner2
except:
traceback.print_exc()
assert(False)
utmod.main(argv=sys.argv)
else:
if os.environ.has_key('XMLRUNNER'):
utmod.main(argv=sys.argv, testRunner=xmlrunner2.XMLTestRunner)
else:
utmod.main(argv=sys.argv)