Tests for repository machinery

Tests Package and bundle creation,
dependency traversal, corresponding shell commands.

Change-Id: I93d2984243a6e89efb901a0510c61ae9fb0cf210
This commit is contained in:
Kirill Zaitsev 2015-03-25 18:52:50 +03:00
parent 2a4454467f
commit 21504e6ad4
4 changed files with 492 additions and 157 deletions

View File

@ -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'))

View File

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

View File

@ -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'])
)

View File

@ -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