diff --git a/muranoclient/tests/test_common.py b/muranoclient/tests/test_common.py deleted file mode 100644 index e92ea2a1..00000000 --- a/muranoclient/tests/test_common.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright (c) 2015 Mirantis, Inc. -# -# Licensed 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 tempfile - -import mock -import requests -import testtools - -from muranoclient.common import utils - - -class UtilsTest(testtools.TestCase): - - def test_file_object_from_file(self): - f_obj = tempfile.NamedTemporaryFile(delete=True) - new_f_obj = utils.File(f_obj).open() - self.assertTrue(hasattr(new_f_obj, 'read')) - - new_f_obj = utils.File(f_obj.name).open() - self.assertTrue(hasattr(new_f_obj, 'read')) - - def test_file_object_file_fails(self): - f_obj = utils.File('') - self.assertRaises(ValueError, f_obj.open) - - def test_file_object_url_fails(self): - resp = requests.Response() - resp.status_code = 400 - resp.raw = StringIO.StringIO("123") - - with mock.patch( - 'requests.get', - mock.Mock(side_effect=lambda k, *args, **kwargs: resp)): - f = utils.File("http://127.0.0.1") - self.assertRaises(ValueError, f.open) - - def test_file_object_url(self): - resp = requests.Response() - resp.raw = StringIO.StringIO("123") - resp.status_code = 200 - with mock.patch( - 'requests.get', - mock.Mock(side_effect=lambda k, *args, **kwargs: resp)): - new_f_obj = utils.File('http://127.0.0.1/').open() - self.assertTrue(hasattr(new_f_obj, 'read')) - - def test_file_object_repo_fails(self): - - resp = requests.Response() - resp.raw = StringIO.StringIO("123") - resp.status_code = 400 - with mock.patch( - 'requests.get', - mock.Mock(side_effect=lambda k, *args, **kwargs: resp)): - self.assertRaises( - ValueError, utils.Package.from_file, - utils.to_url('foo.bar.baz', base_url='http://127.0.0.1')) - - def test_no_repo_url_fails(self): - self.assertRaises(ValueError, utils.to_url, - 'foo.bar.baz', base_url='') - - def test_file_object_repo(self): - resp = requests.Response() - resp.raw = StringIO.StringIO("123") - resp.status_code = 200 - with mock.patch( - 'requests.get', - mock.Mock(side_effect=lambda k, *args, **kwargs: resp)): - new_f_obj = utils.Package.from_file(utils.to_url( - 'foo.bar.baz', base_url='http://')).file() - self.assertTrue(hasattr(new_f_obj, 'read')) diff --git a/muranoclient/tests/test_shell.py b/muranoclient/tests/test_shell.py index cfd61ab2..749c41f0 100644 --- a/muranoclient/tests/test_shell.py +++ b/muranoclient/tests/test_shell.py @@ -12,15 +12,18 @@ # License for the specific language governing permissions and limitations # under the License. +import json +import logging import os import re +import shutil import StringIO import sys import tempfile import fixtures import mock -import requests +import requests_mock import six from testtools import matchers @@ -28,8 +31,11 @@ from muranoclient.common import utils from muranoclient.openstack.common.apiclient import exceptions import muranoclient.shell from muranoclient.tests import base +from muranoclient.tests import test_utils from muranoclient.v1 import shell as v1_shell +make_pkg = test_utils.make_pkg + FIXTURE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), 'fixture_data')) # RESULT_PACKAGE = os.path.join(FIXTURE_DIR, 'test-app.zip') @@ -47,8 +53,10 @@ FAKE_ENV2 = {'OS_USERNAME': 'username', class TestArgs(object): version = '' - murano_repo_url = '' + murano_repo_url = 'http://127.0.0.1' exists_action = '' + is_public = False + categories = [] class ShellTest(base.TestCaseShell): @@ -70,6 +78,17 @@ class ShellTest(base.TestCaseShell): 'muranoclient.common.http.HTTPClient.get_proxy_url', mock.MagicMock)) + # To prevent log descriptors from being closed during + # shell tests set a custom StreamHandler + self.logger = logging.getLogger() + self.logger.level = logging.DEBUG + self.stream_handler = logging.StreamHandler(sys.stdout) + self.logger.addHandler(self.stream_handler) + + def tearDown(self): + super(ShellTest, self).tearDown() + self.logger.removeHandler(self.stream_handler) + def shell(self, argstr, exitcodes=(0,)): orig = sys.stdout orig_stderr = sys.stderr @@ -265,8 +284,6 @@ class ShellTest(base.TestCaseShell): class ShellPackagesOperations(ShellTest): - def tearDown(self): - super(ShellPackagesOperations, self).tearDown() def test_create_hot_based_package(self): self.useFixture(fixtures.MonkeyPatch( @@ -299,9 +316,8 @@ class ShellPackagesOperations(ShellTest): "Application package " "is available at {0}".format(RESULT_PACKAGE)) - @mock.patch('muranoclient.common.utils.Package.images') - def test_package_import(self, mock_images): - mock_images.return_value = [] + @mock.patch('muranoclient.common.utils.Package.from_file') + def test_package_import(self, from_file): args = TestArgs() with tempfile.NamedTemporaryFile() as f: RESULT_PACKAGE = f.name @@ -309,82 +325,59 @@ class ShellPackagesOperations(ShellTest): args.categories = ['Cat1', 'Cat2 with space'] args.is_public = True - result = {RESULT_PACKAGE: utils.Package.from_file( - StringIO.StringIO("123"))} - with mock.patch( - 'muranoclient.common.utils.Package.manifest') as man_mock: - man_mock.__getitem__.side_effect = [args.filename] - with mock.patch( - 'muranoclient.common.utils.Package.requirements', - mock.Mock(side_effect=lambda *args, **kw: result)): - v1_shell.do_package_import(self.client, args) + pkg = make_pkg({'FullName': RESULT_PACKAGE}) + from_file.return_value = utils.Package(utils.File(pkg)) - self.client.packages.create.assert_called_once_with( - {'categories': ['Cat1', 'Cat2 with space'], 'is_public': True}, - {RESULT_PACKAGE: mock.ANY}, - ) + v1_shell.do_package_import(self.client, args) - @mock.patch('muranoclient.common.utils.Package.images') - def test_package_import_no_categories(self, mock_images): - mock_images.return_value = [] + self.client.packages.create.assert_called_once_with({ + 'categories': ['Cat1', 'Cat2 with space'], + 'is_public': True + }, {RESULT_PACKAGE: mock.ANY},) + + @mock.patch('muranoclient.common.utils.Package.from_file') + def test_package_import_no_categories(self, from_file): args = TestArgs() + with tempfile.NamedTemporaryFile() as f: RESULT_PACKAGE = f.name + pkg = make_pkg({'FullName': RESULT_PACKAGE}) + from_file.return_value = utils.Package(utils.File(pkg)) args.filename = RESULT_PACKAGE args.categories = None args.is_public = False - result = {RESULT_PACKAGE: utils.Package.from_file( - StringIO.StringIO("123"))} - - with mock.patch( - 'muranoclient.common.utils.Package.manifest') as man_mock: - man_mock.__getitem__.side_effect = [args.filename] - with mock.patch( - 'muranoclient.common.utils.Package.requirements', - mock.Mock(side_effect=lambda *args, **kw: result)): - v1_shell.do_package_import(self.client, args) + v1_shell.do_package_import(self.client, args) self.client.packages.create.assert_called_once_with( {'is_public': False}, {RESULT_PACKAGE: mock.ANY}, ) - @mock.patch('muranoclient.common.utils.Package.images') - def test_package_import_url(self, mock_images): - mock_images.return_value = [] + @requests_mock.mock() + @mock.patch('muranoclient.common.utils.Package.from_file') + def test_package_import_url(self, rm, from_file): args = TestArgs() - args.filename = "http://127.0.0.1/test_package.zip" args.categories = None args.is_public = False - resp = requests.Response() - resp.status_code = 200 - resp.raw = StringIO.StringIO("123") - result = {args.filename: utils.Package.from_file( - StringIO.StringIO("123"))} - with mock.patch( - 'muranoclient.common.utils.Package.manifest') as man_mock: - man_mock.__getitem__.side_effect = [args.filename] - with mock.patch( - 'requests.get', - mock.Mock(side_effect=lambda k, *args, **kw: resp)): - with mock.patch( - 'muranoclient.common.utils.Package.requirements', - mock.Mock(side_effect=lambda *args, **kw: result)): + pkg = make_pkg({'FullName': 'test_package'}) + from_file.return_value = utils.Package(utils.File(pkg)) - v1_shell.do_package_import(self.client, args) + rm.get(args.filename, body=make_pkg({'FullName': 'test_package'})) + + v1_shell.do_package_import(self.client, args) self.client.packages.create.assert_called_once_with( {'is_public': False}, - {args.filename: mock.ANY}, + {'test_package': mock.ANY}, ) - @mock.patch('muranoclient.common.utils.Package.images') - def test_package_import_by_name(self, mock_images): - mock_images.return_value = [] + @requests_mock.mock() + @mock.patch('muranoclient.common.utils.Package.from_file') + def test_package_import_by_name(self, rm, from_file): args = TestArgs() args.filename = "io.test.apps.test_application" @@ -392,25 +385,182 @@ class ShellPackagesOperations(ShellTest): args.is_public = False args.murano_repo_url = "http://127.0.0.1" - resp = requests.Response() - resp.status_code = 200 - resp.raw = StringIO.StringIO("123") - result = {args.filename: utils.Package.from_file( - StringIO.StringIO("123"))} - with mock.patch( - 'muranoclient.common.utils.Package.manifest') as man_mock: - man_mock.__getitem__.side_effect = [args.filename] - with mock.patch( - 'requests.get', - mock.Mock(side_effect=lambda k, *args, **kw: resp)): - with mock.patch( - 'muranoclient.common.utils.Package.requirements', - mock.Mock(side_effect=lambda *args, **kw: result)): + pkg = make_pkg({'FullName': args.filename}) + from_file.return_value = utils.Package(utils.File(pkg)) - v1_shell.do_package_import(self.client, args) + rm.get(args.murano_repo_url + '/apps/' + args.filename + '.zip', + body=make_pkg({'FullName': 'first_app'})) + + v1_shell.do_package_import(self.client, args) self.assertTrue(self.client.packages.create.called) self.client.packages.create.assert_called_once_with( {'is_public': False}, {args.filename: mock.ANY}, ) + + @requests_mock.mock() + def test_import_bundle_by_name(self, m): + """Asserts bundle import calls packages create once for each pkg.""" + pkg1 = make_pkg({'FullName': 'first_app'}) + pkg2 = make_pkg({'FullName': 'second_app'}) + + m.get(TestArgs.murano_repo_url + '/apps/first_app.zip', body=pkg1) + m.get(TestArgs.murano_repo_url + '/apps/second_app.1.0.zip', + body=pkg2) + s = StringIO.StringIO() + bundle_contents = {'Packages': [ + {'Name': 'first_app'}, + {'Name': 'second_app', 'Version': '1.0'} + ]} + json.dump(bundle_contents, s) + s.seek(0) + + m.get(TestArgs.murano_repo_url + '/bundles/test_bundle.bundle', + body=s) + + args = TestArgs() + args.filename = "test_bundle" + + v1_shell.do_bundle_import(self.client, args) + + self.client.packages.create.assert_has_calls( + [ + mock.call({'is_public': False}, {'first_app': mock.ANY}), + mock.call({'is_public': False}, {'second_app': mock.ANY}), + ], any_order=True, + ) + + @requests_mock.mock() + def test_import_bundle_dependencies(self, m): + """Asserts bundle import calls packages create once for each pkg, + including dependencies. + """ + pkg1 = make_pkg( + {'FullName': 'first_app', 'Require': {'second_app': '1.0'}, }) + pkg2 = make_pkg({'FullName': 'second_app'}) + + m.get(TestArgs.murano_repo_url + '/apps/first_app.zip', body=pkg1) + m.get(TestArgs.murano_repo_url + '/apps/second_app.1.0.zip', + body=pkg2) + s = StringIO.StringIO() + + # bundle only contains 1st package + bundle_contents = {'Packages': [ + {'Name': 'first_app'}, + ]} + json.dump(bundle_contents, s) + s.seek(0) + + m.get(TestArgs.murano_repo_url + '/bundles/test_bundle.bundle', + body=s) + + args = TestArgs() + args.filename = "test_bundle" + + v1_shell.do_bundle_import(self.client, args) + + self.client.packages.create.assert_has_calls( + [ + mock.call({'is_public': False}, {'first_app': mock.ANY}), + mock.call({'is_public': False}, {'second_app': mock.ANY}), + ], any_order=True, + ) + + @requests_mock.mock() + def test_import_bundle_by_url(self, m): + """Asserts bundle import calls packages create once for each pkg.""" + pkg1 = make_pkg({'FullName': 'first_app'}) + pkg2 = make_pkg({'FullName': 'second_app'}) + + m.get(TestArgs.murano_repo_url + '/apps/first_app.zip', body=pkg1) + m.get(TestArgs.murano_repo_url + '/apps/second_app.1.0.zip', + body=pkg2) + s = StringIO.StringIO() + bundle_contents = {'Packages': [ + {'Name': 'first_app'}, + {'Name': 'second_app', 'Version': '1.0'} + ]} + json.dump(bundle_contents, s) + s.seek(0) + + url = 'http://127.0.0.2/test_bundle.bundle' + m.get(url, body=s) + + args = TestArgs() + args.filename = url + + v1_shell.do_bundle_import(self.client, args) + + self.client.packages.create.assert_has_calls( + [ + mock.call({'is_public': False}, {'first_app': mock.ANY}), + mock.call({'is_public': False}, {'second_app': mock.ANY}), + ], any_order=True, + ) + + @requests_mock.mock() + def test_import_bundle_wrong_url(self, m): + url = 'http://127.0.0.2/test_bundle.bundle' + m.get(url, status_code=404) + + args = TestArgs() + args.filename = url + + self.assertRaises(ValueError, v1_shell.do_bundle_import, + self.client, args) + self.assertFalse(self.client.packages.create.called) + + @requests_mock.mock() + def test_import_bundle_no_bundle(self, m): + url = 'http://127.0.0.1/bundles/test_bundle.bundle' + m.get(url, status_code=404) + + args = TestArgs() + args.filename = "test_bundle" + + self.assertRaises(ValueError, v1_shell.do_bundle_import, + self.client, args) + self.assertFalse(self.client.packages.create.called) + + @requests_mock.mock() + def test_import_local_bundle(self, m): + """Asserts local bundles are first searched locally.""" + tmp_dir = tempfile.mkdtemp() + bundle_file = os.path.join(tmp_dir, 'bundle.bundle') + with open(os.path.join(tmp_dir, 'bundle.bundle'), 'w') as f: + + bundle_contents = {'Packages': [ + {'Name': 'first_app'}, + {'Name': 'second_app', 'Version': '1.0'} + ]} + json.dump(bundle_contents, f) + + pkg1 = make_pkg({'FullName': 'first_app', + 'Require': {'third_app': None}}) + pkg2 = make_pkg({'FullName': 'second_app'}) + pkg3 = make_pkg({'FullName': 'third_app'}) + with open(os.path.join(tmp_dir, 'first_app'), 'w') as f: + f.write(pkg1.read()) + with open(os.path.join(tmp_dir, 'third_app'), 'w') as f: + f.write(pkg3.read()) + + m.get(TestArgs.murano_repo_url + '/apps/first_app.zip', + status_code=404) + m.get(TestArgs.murano_repo_url + '/apps/second_app.1.0.zip', + body=pkg2) + m.get(TestArgs.murano_repo_url + '/apps/third_app.zip', + status_code=404) + + args = TestArgs() + args.filename = bundle_file + v1_shell.do_bundle_import(self.client, args) + + self.client.packages.create.assert_has_calls( + [ + mock.call({'is_public': False}, {'first_app': mock.ANY}), + mock.call({'is_public': False}, {'second_app': mock.ANY}), + mock.call({'is_public': False}, {'third_app': mock.ANY}), + ], any_order=True, + ) + shutil.rmtree(tmp_dir) diff --git a/muranoclient/tests/test_utils.py b/muranoclient/tests/test_utils.py new file mode 100644 index 00000000..65f7a5da --- /dev/null +++ b/muranoclient/tests/test_utils.py @@ -0,0 +1,270 @@ +# Copyright (c) 2015 Mirantis, Inc. +# +# Licensed 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 json +import os.path +import StringIO +import tempfile +import zipfile + +import mock +import requests +import requests_mock +import testtools +import yaml + + +from muranoclient.common import utils + + +class FileTest(testtools.TestCase): + + def test_file_object_from_file(self): + f_obj = tempfile.NamedTemporaryFile(delete=True) + new_f_obj = utils.File(f_obj).open() + self.assertTrue(hasattr(new_f_obj, 'read')) + + new_f_obj = utils.File(f_obj.name).open() + self.assertTrue(hasattr(new_f_obj, 'read')) + + def test_file_object_file_fails(self): + f_obj = utils.File('') + self.assertRaises(ValueError, f_obj.open) + + def test_file_object_url_fails(self): + resp = requests.Response() + resp.status_code = 400 + resp.raw = StringIO.StringIO("123") + + with mock.patch( + 'requests.get', + mock.Mock(side_effect=lambda k, *args, **kwargs: resp)): + f = utils.File("http://127.0.0.1") + self.assertRaises(ValueError, f.open) + + def test_file_object_url(self): + resp = requests.Response() + resp.raw = StringIO.StringIO("123") + resp.status_code = 200 + with mock.patch( + 'requests.get', + mock.Mock(side_effect=lambda k, *args, **kwargs: resp)): + new_f_obj = utils.File('http://127.0.0.1/').open() + self.assertTrue(hasattr(new_f_obj, 'read')) + + +def make_pkg(manifest_override, image_dicts=None): + manifest = { + 'Author': '', + 'Classes': {'foo': 'foo.yaml'}, + 'Description': '', + 'Format': 1.0, + 'FullName': '', + 'Name': 'Apache HTTP Server', + 'Type': 'Application'} + manifest.update(manifest_override) + file_obj = StringIO.StringIO() + zfile = zipfile.ZipFile(file_obj, "a") + zfile.writestr('manifest.yaml', yaml.dump(manifest)) + if image_dicts: + images_list = [] + default_image_spec = { + 'ContainerFormat': 'bare', + 'DiskFormat': 'qcow2', + 'Hash': 'd41d8cd98f00b204e9800998ecf8427e', + 'Name': '', + } + for image_dict in image_dicts: + image_spec = default_image_spec.copy() + image_spec.update(image_dict) + images_list.append(image_spec) + images = {'Images': images_list, } + zfile.writestr('images.lst', yaml.dump(images)) + zfile.close() + file_obj.seek(0) + return file_obj + + +class PackageTest(testtools.TestCase): + base_url = "http://127.0.0.1" + + @requests_mock.mock() + def test_from_location_local_file(self, m): + temp = tempfile.NamedTemporaryFile() + pkg = make_pkg({'FullName': 'single_app'}) + + temp.write(pkg.read()) + temp.flush() + path, name = os.path.split(temp.name) + + # ensure we do not go to base url + m.get(self.base_url + '/apps/{0}.zip'.format(name), status_code=404) + + self.assertEqual('single_app', utils.Package.from_location( + name=name, base_url=self.base_url, + path=path, + ).manifest['FullName']) + + @requests_mock.mock() + def test_from_location_url(self, m): + """Test that url overrides name specification.""" + + pkg = make_pkg({'FullName': 'single_app'}) + m.get('http://127.0.0.2/apps/single_app.zip', body=pkg) + m.get(self.base_url + '/apps/single_app.zip', status_code=404) + + self.assertEqual('single_app', utils.Package.from_location( + name='single_app', base_url=self.base_url, + url="http://127.0.0.2/apps/single_app.zip", + ).manifest['FullName']) + + @requests_mock.mock() + def test_from_location(self, m): + """Test from location url requesting mechanism.""" + pkg = make_pkg({'FullName': 'single_app'}) + pkg_ver = make_pkg({'FullName': 'single_app'}) + m.get(self.base_url + '/apps/single_app.zip', body=pkg) + m.get(self.base_url + '/apps/single_app.1.0.zip', body=pkg_ver) + m.get(self.base_url + '/apps/single_app.2.0.zip', status_code=404) + + self.assertEqual('single_app', utils.Package.from_location( + name='single_app', base_url=self.base_url).manifest['FullName']) + + self.assertEqual('single_app', utils.Package.from_location( + name='single_app', + version='1.0', + base_url=self.base_url).manifest['FullName']) + self.assertRaises( + ValueError, + utils.Package.from_location, + name='single_app', + version='2.0', + base_url=self.base_url) + + def test_no_requirements(self): + pkg = make_pkg({'FullName': 'single_app'}) + app = utils.Package.fromFile(pkg) + reqs = app.requirements(base_url=self.base_url) + self.assertEqual(reqs, {'single_app': app}) + + @requests_mock.mock() + def test_requirements(self, m): + """Test that dependencies are parsed correctly.""" + + pkg3 = make_pkg({'FullName': 'dep_of_dep'}) + pkg2 = make_pkg({'FullName': 'dep_app', 'Require': { + 'dep_of_dep': "1.0"}, }) + pkg1 = make_pkg({'FullName': 'main_app', 'Require': { + 'dep_app': None}, }) + + m.get(self.base_url + '/apps/main_app.zip', body=pkg1) + m.get(self.base_url + '/apps/dep_app.zip', body=pkg2) + m.get(self.base_url + '/apps/dep_of_dep.1.0.zip', body=pkg3) + app = utils.Package.fromFile(pkg1) + reqs = app.requirements(base_url=self.base_url) + + self.assertEqual( + reqs, + {'main_app': app, 'dep_app': mock.ANY, 'dep_of_dep': mock.ANY}) + + @requests_mock.mock() + def test_cyclic_requirements(self, m): + """Test that a cyclic dependency would be handled correctly.""" + pkg3 = make_pkg({'FullName': 'dep_of_dep', 'Require': { + 'main_app': None, 'dep_app': None}, }) + pkg2 = make_pkg({'FullName': 'dep_app', 'Require': { + 'dep_of_dep': None, 'main_app': None}, }) + pkg1 = make_pkg({'FullName': 'main_app', 'Require': { + 'dep_app': None, 'dep_of_dep': None}, }) + + m.get(self.base_url + '/apps/main_app.zip', body=pkg1) + m.get(self.base_url + '/apps/dep_app.zip', body=pkg2) + m.get(self.base_url + '/apps/dep_of_dep.zip', body=pkg3) + app = utils.Package.fromFile(pkg1) + reqs = app.requirements(base_url=self.base_url) + + self.assertEqual( + reqs, + {'main_app': app, 'dep_app': mock.ANY, 'dep_of_dep': mock.ANY}) + + def test_images(self): + pkg = make_pkg({}) + app = utils.Package.fromFile(pkg) + self.assertEqual([], app.images()) + + pkg = make_pkg( + {}, [{'Name': 'test.qcow2'}, {'Name': 'test2.qcow2'}]) + app = utils.Package.fromFile(pkg) + self.assertEqual( + set(['test.qcow2', 'test2.qcow2']), + set([img['Name'] for img in app.images()])) + + def test_file_object_repo_fails(self): + resp = requests.Response() + resp.raw = StringIO.StringIO("123") + resp.status_code = 400 + with mock.patch( + 'requests.get', + mock.Mock(side_effect=lambda k, *args, **kwargs: resp)): + self.assertRaises( + ValueError, utils.Package.from_location, + name='foo.bar.baz', base_url='http://127.0.0.1') + + def test_no_repo_url_fails(self): + self.assertRaises(ValueError, utils.Package.from_location, + name='foo.bar.baz', base_url='') + + def test_file_object_repo(self): + resp = requests.Response() + resp.raw = StringIO.StringIO("123") + resp.status_code = 200 + with mock.patch( + 'requests.get', + mock.Mock(side_effect=lambda k, *args, **kwargs: resp)): + new_f_obj = utils.Package.from_location( + name='foo.bar.baz', base_url='http://127.0.0.1').file() + self.assertTrue(hasattr(new_f_obj, 'read')) + + +class BundleTest(testtools.TestCase): + base_url = "http://127.0.0.1" + + @requests_mock.mock() + def test_packages(self, m): + s = StringIO.StringIO() + bundle_contents = {'Packages': [ + {'Name': 'first_app'}, + {'Name': 'second_app', 'Version': '1.0'} + ]} + json.dump(bundle_contents, s) + s.seek(0) + bundle = utils.Bundle.from_file(s) + self.assertEqual( + set([p['Name'] for p in bundle.package_specs()]), + set(['first_app', 'second_app']), + ) + + # setup packages + pkg1 = make_pkg({'FullName': 'first_app'}) + pkg2 = make_pkg({'FullName': 'second_app'}) + + m.get(self.base_url + '/apps/first_app.zip', body=pkg1) + m.get(self.base_url + '/apps/second_app.1.0.zip', body=pkg2) + self.assertEqual( + set([p.manifest['FullName'] + for p in + bundle.packages(base_url=self.base_url)]), + set(['first_app', 'second_app']) + ) diff --git a/test-requirements.txt b/test-requirements.txt index c45f1d5d..2476fb5c 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -7,6 +7,7 @@ coverage>=3.6 discover fixtures>=0.3.14 mock>=1.0 +requests-mock>=0.6.0 # Apache-2.0 tempest-lib>=0.4.0 testrepository>=0.0.18 testscenarios>=0.4