Skip to content

Commit

Permalink
Merge pull request apache#1396 from Kami/run_unit_tests_on_multiple_oses
Browse files Browse the repository at this point in the history
Also run unit tests on Windows using Python 3.7
  • Loading branch information
Kami authored Dec 26, 2019
2 parents c69df0f + 558bd86 commit 043bb6d
Show file tree
Hide file tree
Showing 12 changed files with 98 additions and 61 deletions.
10 changes: 10 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ matrix:
- name: Unit Tests, Installation Checks (Python 3.7)
python: 3.7
before_script: TOX_ENV=py3.7,py3.7-dist,py3.7-dist-wheel
- name: Unit Tests (Python 3.7 on Windows)
os: windows
python: 3.7
language: shell
before_install:
- choco install python --version 3.7.5
- export PATH="/c/Python:/c/Python/Scripts:$PATH"
- python -m pip install --upgrade pip
before_script: TOX_ENV=py3.7-windows
env: PATH=/c/Python37:/c/Python37/Scripts:$PATH
- name: Unit Tests (Python 3.8)
python: 3.8
- name: Unit Tests (PyPy 3.5)
Expand Down
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ General
(GITHUB-1377)
[Tomaz Muraus]

- Make sure unit tests now also pass on Windows.
(GITHUB-1396)
[Tomaz Muraus]

Compute
-------

Expand Down
34 changes: 20 additions & 14 deletions libcloud/test/compute/test_deployment.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
'ssh_port', 'ssh_timeout', 'ssh_key', 'timeout',
'max_tries', 'ssh_interface']

FILE_PATH = '{0}home{0}ubuntu{0}relative.sh'.format(os.path.sep)


class MockDeployment(Deployment):

Expand Down Expand Up @@ -137,60 +139,64 @@ def test_script_file_deployment(self):

def test_script_deployment_relative_path(self):
client = Mock()
client.put.return_value = '/home/ubuntu/relative.sh'
client.put.return_value = FILE_PATH
client.run.return_value = ('', '', 0)

sd = ScriptDeployment(script='echo "foo"', name='relative.sh')
sd.run(self.node, client)

client.run.assert_called_once_with('/home/ubuntu/relative.sh')
client.run.assert_called_once_with(FILE_PATH)

def test_script_deployment_absolute_path(self):
client = Mock()
client.put.return_value = '/home/ubuntu/relative.sh'
client.put.return_value = FILE_PATH
client.run.return_value = ('', '', 0)

sd = ScriptDeployment(script='echo "foo"', name='/root/relative.sh')
file_path = '{0}root{0}relative.sh'.format(os.path.sep)

sd = ScriptDeployment(script='echo "foo"', name=file_path)
sd.run(self.node, client)

client.run.assert_called_once_with('/root/relative.sh')
client.run.assert_called_once_with(file_path)

def test_script_deployment_with_arguments(self):
client = Mock()
client.put.return_value = '/home/ubuntu/relative.sh'
client.put.return_value = FILE_PATH
client.run.return_value = ('', '', 0)

file_path = '{0}root{0}relative.sh'.format(os.path.sep)

args = ['arg1', 'arg2', '--option1=test']
sd = ScriptDeployment(script='echo "foo"', args=args,
name='/root/relative.sh')
name=file_path)
sd.run(self.node, client)

expected = '/root/relative.sh arg1 arg2 --option1=test'
expected = '%s arg1 arg2 --option1=test' % (file_path)
client.run.assert_called_once_with(expected)

client.reset_mock()

args = []
sd = ScriptDeployment(script='echo "foo"', args=args,
name='/root/relative.sh')
name=file_path)
sd.run(self.node, client)

expected = '/root/relative.sh'
expected = file_path
client.run.assert_called_once_with(expected)

def test_script_file_deployment_with_arguments(self):
file_path = os.path.abspath(__file__)
client = Mock()
client.put.return_value = '/home/ubuntu/relative.sh'
client.put.return_value = FILE_PATH
client.run.return_value = ('', '', 0)

args = ['arg1', 'arg2', '--option1=test', 'option2']
sfd = ScriptFileDeployment(script_file=file_path, args=args,
name='/root/relative.sh')
name=file_path)

sfd.run(self.node, client)

expected = '/root/relative.sh arg1 arg2 --option1=test option2'
expected = '%s arg1 arg2 --option1=test option2' % (file_path)
client.run.assert_called_once_with(expected)

def test_script_deployment_and_sshkey_deployment_argument_types(self):
Expand Down Expand Up @@ -453,6 +459,7 @@ def create_node(name, image, size, ex_custom_arg_1, ex_custom_arg_2,
self.assertEqual(call_count, 2)

call_count = 0

def create_node(name, image, size, ex_custom_arg_1, ex_custom_arg_2,
ex_foo=None, auth=None, **kwargs):
global call_count
Expand All @@ -471,7 +478,6 @@ def create_node(name, image, size, ex_custom_arg_1, ex_custom_arg_2,
self.assertEqual(self.node.id, node.id)
self.assertEqual(call_count, 2)


@patch('libcloud.compute.base.SSHClient')
@patch('libcloud.compute.ssh')
def test_deploy_node_exception_run_deployment_script(self, mock_ssh_module,
Expand Down
14 changes: 7 additions & 7 deletions libcloud/test/compute/test_ec2.py
Original file line number Diff line number Diff line change
Expand Up @@ -1174,11 +1174,11 @@ def test_ex_modify_subnet_attribute(self):
self.assertTrue(resp)

expected_msg = 'Unsupported attribute: invalid'
self.assertRaisesRegexp(ValueError, expected_msg,
self.driver.ex_modify_subnet_attribute,
subnet,
'invalid',
True)
self.assertRaisesRegex(ValueError, expected_msg,
self.driver.ex_modify_subnet_attribute,
subnet,
'invalid',
True)

def test_ex_delete_subnet(self):
subnet = self.driver.ex_list_subnets()[0]
Expand Down Expand Up @@ -1319,15 +1319,15 @@ def test_params_is_not_simple_type_exception_is_thrown(self):
}

expected_msg = 'dictionary contains an attribute "not" which value'
self.assertRaisesRegexp(ValueError, expected_msg,
self.assertRaisesRegex(ValueError, expected_msg,
self.driver.connection.request, '/', params=params)

params = {
'invalid': [1, 2, 3]
}

expected_msg = 'dictionary contains an attribute "invalid" which value'
self.assertRaisesRegexp(ValueError, expected_msg,
self.assertRaisesRegex(ValueError, expected_msg,
self.driver.connection.request, '/', params=params)


Expand Down
4 changes: 4 additions & 0 deletions libcloud/test/compute/test_ssh_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ def setUp(self):
_init_once()
self.ssh_cli = ParamikoSSHClient(**conn_params)

def tearDown(self):
if 'LIBCLOUD_DEBUG' in os.environ:
del os.environ['LIBCLOUD_DEBUG']

@patch('paramiko.SSHClient', Mock)
def test_create_with_password(self):
conn_params = {'hostname': 'dummy.host.org',
Expand Down
9 changes: 8 additions & 1 deletion libcloud/test/storage/test_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import os
import sys
import platform
import shutil
import unittest
import tempfile
Expand Down Expand Up @@ -62,7 +63,13 @@ def make_tmp_file(self):
return tmppath

def remove_tmp_file(self, tmppath):
os.unlink(tmppath)
try:
os.unlink(tmppath)
except Exception as e:
msg = str(e)
if 'being used by another process' in msg and platform.system().lower() == 'windows':
return
raise e

def test_list_containers_empty(self):
containers = self.driver.list_containers()
Expand Down
4 changes: 2 additions & 2 deletions libcloud/test/storage/test_s3.py
Original file line number Diff line number Diff line change
Expand Up @@ -1068,8 +1068,8 @@ def test_region_keyword_argument(self):

# Invalid region
expected_msg = 'Invalid or unsupported region: foo'
self.assertRaisesRegexp(ValueError, expected_msg, S3StorageDriver,
*self.driver_args, region='foo')
self.assertRaisesRegex(ValueError, expected_msg, S3StorageDriver,
*self.driver_args, region='foo')

# host argument still has precedence over reguin
driver3 = S3StorageDriver(*self.driver_args, region='ap-south-1', host='host1.bar.com')
Expand Down
12 changes: 9 additions & 3 deletions libcloud/test/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@

import os
import sys
import tempfile
import logging

try:
import paramiko
import paramiko # NOQA
have_paramiko = True
except ImportError:
have_paramiko = False
Expand All @@ -34,6 +35,10 @@


class TestUtils(unittest.TestCase):
def tearDown(self):
if 'LIBCLOUD_DEBUG' in os.environ:
del os.environ['LIBCLOUD_DEBUG']

def test_init_once_and_debug_mode(self):
if have_paramiko:
paramiko_logger = logging.getLogger('paramiko')
Expand All @@ -49,7 +54,8 @@ def test_init_once_and_debug_mode(self):
self.assertEqual(paramiko_log_level, logging.INFO)

# Enable debug mode
os.environ['LIBCLOUD_DEBUG'] = '/dev/null'
_, tmp_path = tempfile.mkstemp()
os.environ['LIBCLOUD_DEBUG'] = tmp_path
_init_once()

self.assertTrue(LoggingConnection.log is not None)
Expand All @@ -70,7 +76,7 @@ def test_raises_error(self):
@patch.object(libcloud.requests.packages.chardet, '__version__', '2.2.1')
def test_init_once_detects_bad_yum_install_requests(self, *args):
expected_msg = 'Known bad version of requests detected'
with self.assertRaisesRegexp(AssertionError, expected_msg):
with self.assertRaisesRegex(AssertionError, expected_msg):
_init_once()

@patch.object(libcloud.requests, '__version__', '2.6.0')
Expand Down
46 changes: 25 additions & 21 deletions libcloud/test/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import codecs
import unittest
import warnings
import platform
import os.path
import requests_mock
from itertools import chain
Expand Down Expand Up @@ -65,6 +66,7 @@
def show_warning(msg, cat, fname, lno, file=None, line=None):
WARNINGS_BUFFER.append((msg, cat, fname, lno))


original_func = warnings.showwarning


Expand All @@ -78,6 +80,7 @@ def tearDown(self):
WARNINGS_BUFFER = []
warnings.showwarning = original_func

@unittest.skipIf(platform.system().lower() == 'windows', 'Unsupported on Windows')
def test_guess_file_mime_type(self):
file_path = os.path.abspath(__file__)
mimetype, encoding = libcloud.utils.files.guess_file_mime_type(
Expand Down Expand Up @@ -210,32 +213,32 @@ def iterator():
self.assertEqual(result, b('aaaaaaaaaa'))

def test_read_in_chunks_filelike(self):
class FakeFile(file):
def __init__(self):
self.remaining = 500
class FakeFile(file):
def __init__(self):
self.remaining = 500

def read(self, size):
self.remaining -= 1
if self.remaining == 0:
return ''
return 'b' * (size + 1)
def read(self, size):
self.remaining -= 1
if self.remaining == 0:
return ''
return 'b' * (size + 1)

for index, result in enumerate(libcloud.utils.files.read_in_chunks(
FakeFile(), chunk_size=10,
fill_size=False)):
self.assertEqual(result, b('b' * 11))
for index, result in enumerate(libcloud.utils.files.read_in_chunks(
FakeFile(), chunk_size=10,
fill_size=False)):
self.assertEqual(result, b('b' * 11))

self.assertEqual(index, 498)
self.assertEqual(index, 498)

for index, result in enumerate(libcloud.utils.files.read_in_chunks(
FakeFile(), chunk_size=10,
fill_size=True)):
if index != 548:
self.assertEqual(result, b('b' * 10))
else:
self.assertEqual(result, b('b' * 9))
for index, result in enumerate(libcloud.utils.files.read_in_chunks(
FakeFile(), chunk_size=10,
fill_size=True)):
if index != 548:
self.assertEqual(result, b('b' * 10))
else:
self.assertEqual(result, b('b' * 9))

self.assertEqual(index, 548)
self.assertEqual(index, 548)

def test_exhaust_iterator(self):
def iterator_func():
Expand Down Expand Up @@ -436,5 +439,6 @@ def test_get_response_object():
response = get_response_object('http://test.com/test')
assert response.body == 'data'


if __name__ == '__main__':
sys.exit(unittest.main())
11 changes: 1 addition & 10 deletions libcloud/utils/networking.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

import socket
import struct
import platform

__all__ = [
'is_private_subnet',
Expand Down Expand Up @@ -75,16 +74,8 @@ def is_valid_ip_address(address, family=socket.AF_INET):
:return: ``bool`` True if the provided address is valid.
"""
is_windows = platform.system() == 'Windows'

if is_windows and family == socket.AF_INET6:
raise ValueError('Checking IPv6 addresses is not supported on Windows')

try:
if is_windows:
socket.inet_aton(address)
else:
socket.inet_pton(family, address)
socket.inet_pton(family, address)
except socket.error:
return False

Expand Down
4 changes: 2 additions & 2 deletions libcloud/utils/py3.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,11 +232,11 @@ def assertRaisesRegex(self, *args, **kwargs):
raise ValueError('First argument "self" needs to be an instance '
'of unittest.TestCase')

return getattr(self, 'assertRaisesRegexp')(*args, **kwargs)
return getattr(self, 'assertRaisesRegex')(*args, **kwargs)

def assertRegex(self, *args, **kwargs):
if not isinstance(self, unittest.TestCase):
raise ValueError('First argument "self" needs to be an instance '
'of unittest.TestCase')

return getattr(self, 'assertRegexpMatches')(*args, **kwargs)
return getattr(self, 'assertRegex')(*args, **kwargs)
7 changes: 6 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,19 @@ basepython =
pypypy3.5: pypy3.5
py3.5: python3.5
py3.6: python3.6
{py3.7,docs,checks,lint,pylint,mypy,coverage,docs,py3.7-dist,py3.7-dist-wheel}: python3.7
{py3.7,py3.7-windows,docs,checks,lint,pylint,mypy,coverage,docs,py3.7-dist,py3.7-dist-wheel}: python3.7
py3.8: python3.8
commands = cp libcloud/test/secrets.py-dist libcloud/test/secrets.py
python setup.py test

whitelist_externals = cp
bash
scripts/*.sh
[testenv:py3.7-windows]
deps =
-r{toxinidir}/requirements-tests.txt
lockfile
setuptools==42.0.2

[testenv:py3.7-dist]
# Verify library installs without any dependencies when using python setup.py
Expand Down

0 comments on commit 043bb6d

Please sign in to comment.