Repository: libcloud Updated Branches: refs/heads/trunk 03575ecfd -> 80b17fae9
http://git-wip-us.apache.org/repos/asf/libcloud/blob/04fa0666/libcloud/test/storage/test_backblaze_b2.py ---------------------------------------------------------------------- diff --cc libcloud/test/storage/test_backblaze_b2.py index 728f348,60a20f4..47dc7ce --- a/libcloud/test/storage/test_backblaze_b2.py +++ b/libcloud/test/storage/test_backblaze_b2.py @@@ -1,237 -1,238 +1,238 @@@ -# 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 os -import sys -import tempfile - -import mock - -from libcloud.storage.drivers.backblaze_b2 import BackblazeB2StorageDriver -from libcloud.utils.py3 import httplib -from libcloud.test import unittest -from libcloud.test import StorageMockHttp -from libcloud.test import MockRawResponse -from libcloud.test import MockHttpTestCase -from libcloud.test.file_fixtures import StorageFileFixtures - - -class MockAuthConn(mock.Mock): - account_id = 'abcdefgh' - - -class BackblazeB2StorageDriverTestCase(unittest.TestCase): - driver_klass = BackblazeB2StorageDriver - driver_args = ('a', 'b') - - def setUp(self): - self.driver_klass.connectionCls.authCls = MockAuthConn() - self.driver_klass.connectionCls.conn_classes = ( - None, BackblazeB2MockHttp) - self.driver_klass.connectionCls.rawResponseCls = \ - BackblazeB2MockRawResponse - BackblazeB2MockHttp.type = None - BackblazeB2MockRawResponse.type = None - self.driver = self.driver_klass(*self.driver_args) - - def test_list_containers(self): - containers = self.driver.list_containers() - self.assertEqual(len(containers), 3) - self.assertEqual(containers[0].name, 'test00001') - self.assertEqual(containers[0].extra['id'], '481c37de2e1ab3bf5e150710') - self.assertEqual(containers[0].extra['bucketType'], 'allPrivate') - - def test_list_container_objects(self): - container = self.driver.list_containers()[0] - objects = self.driver.list_container_objects(container=container) - self.assertEqual(len(objects), 4) - self.assertEqual(objects[0].name, '2.txt') - self.assertEqual(objects[0].size, 2) - self.assertEqual(objects[0].extra['fileId'], 'abcd') - self.assertEqual(objects[0].extra['uploadTimestamp'], 1450545966000) - - def test_get_container(self): - container = self.driver.get_container('test00001') - self.assertEqual(container.name, 'test00001') - self.assertEqual(container.extra['id'], '481c37de2e1ab3bf5e150710') - self.assertEqual(container.extra['bucketType'], 'allPrivate') - - def test_get_object(self): - obj = self.driver.get_object('test00001', '2.txt') - self.assertEqual(obj.name, '2.txt') - self.assertEqual(obj.size, 2) - self.assertEqual(obj.extra['fileId'], 'abcd') - self.assertEqual(obj.extra['uploadTimestamp'], 1450545966000) - - def test_create_container(self): - container = self.driver.create_container(container_name='test0005') - self.assertEqual(container.name, 'test0005') - self.assertEqual(container.extra['id'], '681c87aebeaa530f5e250710') - self.assertEqual(container.extra['bucketType'], 'allPrivate') - - def test_delete_container(self): - container = self.driver.list_containers()[0] - result = self.driver.delete_container(container=container) - self.assertTrue(result) - - def test_download_object(self): - container = self.driver.list_containers()[0] - obj = self.driver.list_container_objects(container=container)[0] - _, destination_path = tempfile.mkstemp() - result = self.driver.download_object(obj=obj, destination_path=destination_path, - overwrite_existing=True) - self.assertTrue(result) - - def test_download_object_as_stream(self): - container = self.driver.list_containers()[0] - obj = self.driver.list_container_objects(container=container)[0] - result = self.driver.download_object_as_stream(obj=obj) - result = ''.join([x.decode('utf-8') for x in list(result)]) - self.assertEqual(result, 'ab') - - def test_upload_object(self): - file_path = os.path.abspath(__file__) - container = self.driver.list_containers()[0] - obj = self.driver.upload_object(file_path=file_path, container=container, - object_name='test0007.txt') - self.assertEqual(obj.name, 'test0007.txt') - self.assertEqual(obj.size, 24) - self.assertEqual(obj.extra['fileId'], 'abcde') - - def test_upload_object_via_stream(self): - container = self.driver.list_containers()[0] - file_path = os.path.abspath(__file__) - file = open(file_path, 'rb') - iterator = iter(file) - obj = self.driver.upload_object_via_stream(iterator=iterator, - container=container, - object_name='test0007.txt') - self.assertEqual(obj.name, 'test0007.txt') - self.assertEqual(obj.size, 24) - self.assertEqual(obj.extra['fileId'], 'abcde') - - def test_delete_object(self): - container = self.driver.list_containers()[0] - obj = self.driver.list_container_objects(container=container)[0] - result = self.driver.delete_object(obj=obj) - self.assertTrue(result) - - def test_ex_hide_object(self): - container = self.driver.list_containers()[0] - container_id = container.extra['id'] - obj = self.driver.ex_hide_object(container_id=container_id, - object_name='2.txt') - self.assertEqual(obj.name, '2.txt') - - def test_ex_list_object_versions(self): - container = self.driver.list_containers()[0] - container_id = container.extra['id'] - objects = self.driver.ex_list_object_versions(container_id=container_id) - self.assertEqual(len(objects), 9) - - def test_ex_get_upload_data(self): - container = self.driver.list_containers()[0] - container_id = container.extra['id'] - data = self.driver.ex_get_upload_data(container_id=container_id) - self.assertEqual(data['authorizationToken'], 'nope') - self.assertEqual(data['bucketId'], '481c37de2e1ab3bf5e150710') - self.assertEqual(data['uploadUrl'], 'https://podxxx.backblaze.com/b2api/v1/b2_upload_file/abcd/defg') - - def test_ex_get_upload_url(self): - container = self.driver.list_containers()[0] - container_id = container.extra['id'] - url = self.driver.ex_get_upload_url(container_id=container_id) - self.assertEqual(url, 'https://podxxx.backblaze.com/b2api/v1/b2_upload_file/abcd/defg') - - -class BackblazeB2MockHttp(StorageMockHttp, MockHttpTestCase): - fixtures = StorageFileFixtures('backblaze_b2') - - def _b2api_v1_b2_list_buckets(self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('b2_list_buckets.json') - else: - raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _b2api_v1_b2_list_file_names(self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('b2_list_file_names.json') - else: - raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _b2api_v1_b2_create_bucket(self, method, url, body, headers): - if method == 'POST': - body = self.fixtures.load('b2_create_bucket.json') - else: - raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _b2api_v1_b2_delete_bucket(self, method, url, body, headers): - if method == 'POST': - body = self.fixtures.load('b2_delete_bucket.json') - else: - raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _b2api_v1_b2_delete_file_version(self, method, url, body, headers): - if method == 'POST': - body = self.fixtures.load('b2_delete_file_version.json') - else: - raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _b2api_v1_b2_get_upload_url(self, method, url, body, headers): - # test_upload_object - if method == 'GET': - body = self.fixtures.load('b2_get_upload_url.json') - else: - raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _b2api_v1_b2_upload_file_abcd_defg(self, method, url, body, headers): - # test_upload_object - if method == 'POST': - body = self.fixtures.load('b2_upload_file.json') - else: - raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _b2api_v1_b2_list_file_versions(self, method, url, body, headers): - if method == 'GET': - body = self.fixtures.load('b2_list_file_versions.json') - else: - raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _b2api_v1_b2_hide_file(self, method, url, body, headers): - if method == 'POST': - body = self.fixtures.load('b2_hide_file.json') - else: - raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - -class BackblazeB2MockRawResponse(MockRawResponse): - def _file_test00001_2_txt(self, method, url, body, headers): - # test_download_object - if method == 'GET': - body = 'ab' - else: - raise AssertionError('Unsupported method') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - -if __name__ == '__main__': - sys.exit(unittest.main()) +# 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 os +import sys +import tempfile + +import mock + +from libcloud.storage.drivers.backblaze_b2 import BackblazeB2StorageDriver +from libcloud.utils.py3 import httplib +from libcloud.test import unittest +from libcloud.test import StorageMockHttp +from libcloud.test import MockRawResponse +from libcloud.test import MockHttpTestCase +from libcloud.test.file_fixtures import StorageFileFixtures + + +class MockAuthConn(mock.Mock): + account_id = 'abcdefgh' + + +class BackblazeB2StorageDriverTestCase(unittest.TestCase): + driver_klass = BackblazeB2StorageDriver + driver_args = ('a', 'b') + + def setUp(self): + self.driver_klass.connectionCls.authCls = MockAuthConn() - self.driver_klass.connectionCls.conn_class = BackblazeB2MockHttp ++ self.driver_klass.connectionCls.conn_class = ++ BackblazeB2MockHttp + self.driver_klass.connectionCls.rawResponseCls = \ + BackblazeB2MockRawResponse + BackblazeB2MockHttp.type = None + BackblazeB2MockRawResponse.type = None + self.driver = self.driver_klass(*self.driver_args) + + def test_list_containers(self): + containers = self.driver.list_containers() + self.assertEqual(len(containers), 3) + self.assertEqual(containers[0].name, 'test00001') + self.assertEqual(containers[0].extra['id'], '481c37de2e1ab3bf5e150710') + self.assertEqual(containers[0].extra['bucketType'], 'allPrivate') + + def test_list_container_objects(self): + container = self.driver.list_containers()[0] + objects = self.driver.list_container_objects(container=container) + self.assertEqual(len(objects), 4) + self.assertEqual(objects[0].name, '2.txt') + self.assertEqual(objects[0].size, 2) + self.assertEqual(objects[0].extra['fileId'], 'abcd') + self.assertEqual(objects[0].extra['uploadTimestamp'], 1450545966000) + + def test_get_container(self): + container = self.driver.get_container('test00001') + self.assertEqual(container.name, 'test00001') + self.assertEqual(container.extra['id'], '481c37de2e1ab3bf5e150710') + self.assertEqual(container.extra['bucketType'], 'allPrivate') + + def test_get_object(self): + obj = self.driver.get_object('test00001', '2.txt') + self.assertEqual(obj.name, '2.txt') + self.assertEqual(obj.size, 2) + self.assertEqual(obj.extra['fileId'], 'abcd') + self.assertEqual(obj.extra['uploadTimestamp'], 1450545966000) + + def test_create_container(self): + container = self.driver.create_container(container_name='test0005') + self.assertEqual(container.name, 'test0005') + self.assertEqual(container.extra['id'], '681c87aebeaa530f5e250710') + self.assertEqual(container.extra['bucketType'], 'allPrivate') + + def test_delete_container(self): + container = self.driver.list_containers()[0] + result = self.driver.delete_container(container=container) + self.assertTrue(result) + + def test_download_object(self): + container = self.driver.list_containers()[0] + obj = self.driver.list_container_objects(container=container)[0] + _, destination_path = tempfile.mkstemp() + result = self.driver.download_object(obj=obj, destination_path=destination_path, + overwrite_existing=True) + self.assertTrue(result) + + def test_download_object_as_stream(self): + container = self.driver.list_containers()[0] + obj = self.driver.list_container_objects(container=container)[0] + result = self.driver.download_object_as_stream(obj=obj) + result = ''.join([x.decode('utf-8') for x in list(result)]) + self.assertEqual(result, 'ab') + + def test_upload_object(self): + file_path = os.path.abspath(__file__) + container = self.driver.list_containers()[0] + obj = self.driver.upload_object(file_path=file_path, container=container, + object_name='test0007.txt') + self.assertEqual(obj.name, 'test0007.txt') + self.assertEqual(obj.size, 24) + self.assertEqual(obj.extra['fileId'], 'abcde') + + def test_upload_object_via_stream(self): + container = self.driver.list_containers()[0] + file_path = os.path.abspath(__file__) + file = open(file_path, 'rb') + iterator = iter(file) + obj = self.driver.upload_object_via_stream(iterator=iterator, + container=container, + object_name='test0007.txt') + self.assertEqual(obj.name, 'test0007.txt') + self.assertEqual(obj.size, 24) + self.assertEqual(obj.extra['fileId'], 'abcde') + + def test_delete_object(self): + container = self.driver.list_containers()[0] + obj = self.driver.list_container_objects(container=container)[0] + result = self.driver.delete_object(obj=obj) + self.assertTrue(result) + + def test_ex_hide_object(self): + container = self.driver.list_containers()[0] + container_id = container.extra['id'] + obj = self.driver.ex_hide_object(container_id=container_id, + object_name='2.txt') + self.assertEqual(obj.name, '2.txt') + + def test_ex_list_object_versions(self): + container = self.driver.list_containers()[0] + container_id = container.extra['id'] + objects = self.driver.ex_list_object_versions(container_id=container_id) + self.assertEqual(len(objects), 9) + + def test_ex_get_upload_data(self): + container = self.driver.list_containers()[0] + container_id = container.extra['id'] + data = self.driver.ex_get_upload_data(container_id=container_id) + self.assertEqual(data['authorizationToken'], 'nope') + self.assertEqual(data['bucketId'], '481c37de2e1ab3bf5e150710') + self.assertEqual(data['uploadUrl'], 'https://podxxx.backblaze.com/b2api/v1/b2_upload_file/abcd/defg') + + def test_ex_get_upload_url(self): + container = self.driver.list_containers()[0] + container_id = container.extra['id'] + url = self.driver.ex_get_upload_url(container_id=container_id) + self.assertEqual(url, 'https://podxxx.backblaze.com/b2api/v1/b2_upload_file/abcd/defg') + + +class BackblazeB2MockHttp(StorageMockHttp, MockHttpTestCase): + fixtures = StorageFileFixtures('backblaze_b2') + + def _b2api_v1_b2_list_buckets(self, method, url, body, headers): + if method == 'GET': + body = self.fixtures.load('b2_list_buckets.json') + else: + raise AssertionError('Unsupported method') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _b2api_v1_b2_list_file_names(self, method, url, body, headers): + if method == 'GET': + body = self.fixtures.load('b2_list_file_names.json') + else: + raise AssertionError('Unsupported method') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _b2api_v1_b2_create_bucket(self, method, url, body, headers): + if method == 'POST': + body = self.fixtures.load('b2_create_bucket.json') + else: + raise AssertionError('Unsupported method') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _b2api_v1_b2_delete_bucket(self, method, url, body, headers): + if method == 'POST': + body = self.fixtures.load('b2_delete_bucket.json') + else: + raise AssertionError('Unsupported method') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _b2api_v1_b2_delete_file_version(self, method, url, body, headers): + if method == 'POST': + body = self.fixtures.load('b2_delete_file_version.json') + else: + raise AssertionError('Unsupported method') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _b2api_v1_b2_get_upload_url(self, method, url, body, headers): + # test_upload_object + if method == 'GET': + body = self.fixtures.load('b2_get_upload_url.json') + else: + raise AssertionError('Unsupported method') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _b2api_v1_b2_upload_file_abcd_defg(self, method, url, body, headers): + # test_upload_object + if method == 'POST': + body = self.fixtures.load('b2_upload_file.json') + else: + raise AssertionError('Unsupported method') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _b2api_v1_b2_list_file_versions(self, method, url, body, headers): + if method == 'GET': + body = self.fixtures.load('b2_list_file_versions.json') + else: + raise AssertionError('Unsupported method') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _b2api_v1_b2_hide_file(self, method, url, body, headers): + if method == 'POST': + body = self.fixtures.load('b2_hide_file.json') + else: + raise AssertionError('Unsupported method') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + +class BackblazeB2MockRawResponse(MockRawResponse): + def _file_test00001_2_txt(self, method, url, body, headers): + # test_download_object + if method == 'GET': + body = 'ab' + else: + raise AssertionError('Unsupported method') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + +if __name__ == '__main__': + sys.exit(unittest.main()) http://git-wip-us.apache.org/repos/asf/libcloud/blob/04fa0666/libcloud/test/storage/test_cloudfiles.py ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/04fa0666/libcloud/test/storage/test_s3.py ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/04fa0666/libcloud/test/test_httplib_ssl.py ---------------------------------------------------------------------- diff --cc libcloud/test/test_httplib_ssl.py index a669bb1,f94f737..073cce1 --- a/libcloud/test/test_httplib_ssl.py +++ b/libcloud/test/test_httplib_ssl.py @@@ -16,7 -16,10 +16,9 @@@ import os import sys import os.path - + import ssl + import socket - + import mock from mock import patch import libcloud.security @@@ -84,6 -101,114 +86,113 @@@ class TestHttpLibSSLTests(unittest.Test self.assertTrue(self.httplib_object.ca_cert is not None) + # verify = True, no CA certs are available, exception should be thrown + libcloud.security.CA_CERTS_PATH = [] + + expected_msg = libcloud.security.CA_CERTS_UNAVAILABLE_ERROR_MSG + self.assertRaisesRegexp(RuntimeError, expected_msg, + self.httplib_object._setup_ca_cert) + + @mock.patch('socket.create_connection', mock.MagicMock()) + @mock.patch('socket.socket', mock.MagicMock()) + def test_connect_throws_friendly_error_message_on_ssl_wrap_connection_reset_by_peer(self): + + mock_wrap_socket = None + + if getattr(ssl, 'HAS_SNI', False): + ssl.SSLContext.wrap_socket = mock.MagicMock() + mock_wrap_socket = ssl.SSLContext.wrap_socket + else: + ssl.wrap_socket = mock.MagicMock() + mock_wrap_socket = ssl.wrap_socket + + # Test that we re-throw a more friendly error message in case + # "connection reset by peer" error occurs when trying to establish a + # SSL connection + libcloud.security.VERIFY_SSL_CERT = True + self.httplib_object.verify = True + self.httplib_object.http_proxy_used = False + + # No connection reset by peer, original exception should be thrown + mock_wrap_socket.side_effect = Exception('foo bar fail') + + expected_msg = 'foo bar fail' + self.assertRaisesRegexp(Exception, expected_msg, + self.httplib_object.connect) + + # Connection reset by peer, wrapped exception with friendly error + # message should be thrown + mock_wrap_socket.side_effect = socket.error('Connection reset by peer') + + expected_msg = 'Failed to establish SSL / TLS connection' + self.assertRaisesRegexp(socket.error, expected_msg, + self.httplib_object.connect) + + # Same error but including errno + with self.assertRaises(socket.error) as cm: + mock_wrap_socket.side_effect = socket.error(104, 'Connection reset by peer') + self.httplib_object.connect() + + e = cm.exception + self.assertEqual(e.errno, 104) + self.assertTrue(expected_msg in str(e)) + + # Test original exception is propagated correctly on non reset by peer + # error + with self.assertRaises(socket.error) as cm: + mock_wrap_socket.side_effect = socket.error(105, 'Some random error') + self.httplib_object.connect() + + e = cm.exception + self.assertEqual(e.errno, 105) + self.assertTrue('Some random error' in str(e)) + + def test_certifi_ca_bundle_in_search_path(self): + mock_certifi_ca_bundle_path = '/certifi/bundle/path' + + # Certifi not available + import libcloud.security + reload(libcloud.security) + + original_length = len(libcloud.security.CA_CERTS_PATH) + + self.assertTrue(mock_certifi_ca_bundle_path not in + libcloud.security.CA_CERTS_PATH) + + # Certifi is available + mock_certifi = mock.Mock() + mock_certifi.where.return_value = mock_certifi_ca_bundle_path + sys.modules['certifi'] = mock_certifi + + # Certifi CA bundle path should be injected at the begining of search list + import libcloud.security + reload(libcloud.security) + + self.assertEqual(libcloud.security.CA_CERTS_PATH[0], + mock_certifi_ca_bundle_path) + self.assertEqual(len(libcloud.security.CA_CERTS_PATH), + (original_length + 1)) + + # Certifi is available, but USE_CERTIFI is set to False + os.environ['LIBCLOUD_SSL_USE_CERTIFI'] = 'false' + + import libcloud.security + reload(libcloud.security) + + self.assertTrue(mock_certifi_ca_bundle_path not in + libcloud.security.CA_CERTS_PATH) + self.assertEqual(len(libcloud.security.CA_CERTS_PATH), original_length) + + # And enabled + os.environ['LIBCLOUD_SSL_USE_CERTIFI'] = 'true' + + import libcloud.security + reload(libcloud.security) + + self.assertEqual(libcloud.security.CA_CERTS_PATH[0], + mock_certifi_ca_bundle_path) + self.assertEqual(len(libcloud.security.CA_CERTS_PATH), + (original_length + 1)) - if __name__ == '__main__': sys.exit(unittest.main()) http://git-wip-us.apache.org/repos/asf/libcloud/blob/04fa0666/libcloud/test/test_init.py ---------------------------------------------------------------------- diff --cc libcloud/test/test_init.py index d7069c3,97beacc..d512d3b --- a/libcloud/test/test_init.py +++ b/libcloud/test/test_init.py @@@ -24,9 -24,12 +24,10 @@@ try except ImportError: have_paramiko = False + import libcloud from libcloud import _init_once +from libcloud.utils.loggingconnection import LoggingConnection - + from libcloud.base import DriverTypeNotFoundError -from libcloud.common.base import LoggingHTTPConnection -from libcloud.common.base import LoggingHTTPSConnection - from libcloud.test import unittest http://git-wip-us.apache.org/repos/asf/libcloud/blob/04fa0666/requirements-tests.txt ---------------------------------------------------------------------- diff --cc requirements-tests.txt index 22317b2,b409664..e32eebf --- a/requirements-tests.txt +++ b/requirements-tests.txt @@@ -1,5 -1,7 +1,7 @@@ pep8>=1.7.0,<1.8 flake8>=2.5.1,<2.6 + astroid>=1.4.5,<1.5 + pylint>=1.5.5,<1.6 mock>=1.0.1,<1.1 - requests - requests_mock + coveralls -coverage<4.0 ++coverage<4.0 http://git-wip-us.apache.org/repos/asf/libcloud/blob/04fa0666/setup.py ----------------------------------------------------------------------