diff --git a/setup.py b/setup.py
index 290615579af122ee51a3d79c872629ba925665c5..aed739462799b6493957ae8cb0b051349a564e6e 100644
--- a/setup.py
+++ b/setup.py
@@ -21,7 +21,7 @@ setup(
description='OCCI to Openstack/Cyclades API bridge',
url='http://code.grnet.gr/projects/snf-occi',
license='GPLv3',
- packages=['soi', ],
+ packages=['soi', 'soi.tests'],
entry_points='''
[paste.app_factory]
snf_occi_app=soi:main
diff --git a/soi/compute.py b/soi/compute.py
index 5881bd8d4489ab4cbd94c2f325c23f00796d36ec..ffeb902e282229f2140b1b2bf721cc9f56968626 100644
--- a/soi/compute.py
+++ b/soi/compute.py
@@ -142,32 +142,21 @@ def snf_delete_server(cls, req, server_id):
def snf_run_action(cls, req, action, server_id):
"""Synnefo: server actions"""
-
- actions_map = {
- "stop": {"kwargs": {"server_id": server_id,
- "json_data": {"shutdown": {}}
- }
- },
-
- "start": {"kwargs": {"server_id": server_id,
- "json_data": {"start": {}}
- }
- },
- "restart": {"kwargs": {"server_id": server_id,
- "json_data": {"reboot": {"type": "SOFT"}}
- }
- }
- }
try:
- action = actions_map[action]
- req.environ['service_type'] = 'compute'
- req.environ['method_name'] = 'servers_action_post'
- req.environ.update(action)
- req.get_response(cls.app)
+ json_data = {
+ 'start': {'start': {}},
+ 'stop': {'shutdown': {}},
+ 'restart': {'reboot': {'type': 'SOFT'}}
+ }[action]
except KeyError:
raise webob.exc.HTTPNotImplemented(
explanation='Action {0} not supported'.format(action))
+ req.environ['service_type'] = 'compute'
+ req.environ['method_name'] = 'servers_action_post'
+ req.environ['kwargs'] = {'server_id': server_id, 'json_data': json_data}
+ req.get_response(cls.app)
+
function_map = {
'index': snf_index,
diff --git a/soi/tests/unit/__init__.py b/soi/tests/__init__.py
similarity index 51%
rename from soi/tests/unit/__init__.py
rename to soi/tests/__init__.py
index 25fdd3b3e2d2cd929817c3fd7ee78483ae5c8348..de12dcc5e2963e8dd4150e14f4d3611e7d7ded5f 100644
--- a/soi/tests/unit/__init__.py
+++ b/soi/tests/__init__.py
@@ -12,31 +12,3 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-"""
-This it the entry point for paste deploy .
-
-Paste config file needs to point to egg:::
-
-use = egg:snfOCCI#sample_app
-
-sample_app entry point is defined in setup.py:
-
-entry_points='''
-[paste.app_factory]
-sample_app = soi:main
-''',
-
-which point to this function call (:function).
-"""
-
-from soi import wsgi
-from soi import synnefo
-
-# W0613:unused args
-# pylint: disable=W0613
-
-
-def main(global_config, **settings):
- """This is the entry point for paste into the Synnefo OCCI Interface"""
- factory = wsgi.SNFOCCIMiddleware.factory({})
- return factory(synnefo.call_kamaki)
diff --git a/soi/tests/fakes.py b/soi/tests/fakes.py
new file mode 100644
index 0000000000000000000000000000000000000000..2b34cdd5d365d1445da72548acb725ff62836777
--- /dev/null
+++ b/soi/tests/fakes.py
@@ -0,0 +1,31 @@
+# Copyright (C) 2016 GRNET S.A.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 for more details.
+#
+# You should have received a copy of the GNU General Public License
+
+
+class FakeReq:
+ """use it for testing"""
+ def __init__(self, *args, **kwargs):
+ self.environ = dict()
+
+ def get_response(self, *args, **kwargs):
+ """Don't do enything"""
+
+
+class DummyClass:
+ """use it for testing"""
+ def app(self, *args, **kwargs):
+ """inner app"""
+
+ def get_from_response(self, *args, **kwargs):
+ """Don't do enything"""
diff --git a/soi/tests/unit/compute.py b/soi/tests/unit/compute.py
new file mode 100644
index 0000000000000000000000000000000000000000..e368872a621abbbeac29b5817eb02ebb6c66910d
--- /dev/null
+++ b/soi/tests/unit/compute.py
@@ -0,0 +1,328 @@
+# Copyright (C) 2016 GRNET S.A.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 for more details.
+#
+# You should have received a copy of the GNU General Public License
+
+from soi.tests import fakes
+from soi import compute
+from mock import patch
+
+
+@patch('soi.tests.fakes.DummyClass.get_from_response', return_value='g f r')
+@patch('soi.tests.fakes.FakeReq.get_response', return_value='my response')
+def test_snf_index(gr, gfr):
+ """Test snf_index"""
+ cls, req = fakes.DummyClass(), fakes.FakeReq()
+ r = compute.snf_index(cls, req)
+ assert r == 'g f r'
+ assert req.environ == dict(
+ service_type='compute',
+ method_name='servers_get')
+ gr.assert_called_once_with(cls.app)
+ gfr.assert_called_once_with('my response', 'servers', [])
+
+
+@patch('soi.tests.fakes.DummyClass.get_from_response', return_value='g f r')
+@patch('soi.tests.fakes.FakeReq.get_response', return_value='my response')
+def test_snf_get_flavors(gr, gfr):
+ """Test snf_get_flavors"""
+ cls, req = fakes.DummyClass(), fakes.FakeReq()
+ r = compute.snf_get_flavors(cls, req)
+ assert r == 'g f r'
+ assert req.environ == dict(
+ service_type='compute',
+ method_name='flavors_get',
+ kwargs=dict(detail=True))
+ gr.assert_called_once_with(cls.app)
+ gfr.assert_called_once_with('my response', 'flavors', [])
+
+
+@patch('soi.tests.fakes.DummyClass.get_from_response', return_value='g f r')
+@patch('soi.tests.fakes.FakeReq.get_response', return_value='my response')
+def test_snf_get_images(gr, gfr):
+ """Test snf_get_images"""
+ cls, req = fakes.DummyClass(), fakes.FakeReq()
+ r = compute.snf_get_images(cls, req)
+ assert r == 'g f r'
+ assert req.environ == dict(
+ service_type='compute',
+ method_name='images_get',
+ kwargs=dict(detail=True))
+ gr.assert_called_once_with(cls.app)
+ gfr.assert_called_once_with('my response', 'images', [])
+
+
+def test__openstackify_addresses():
+ """Test _openstackify_addresses"""
+ addresses = {
+ '12345': [{
+ 'version': '4',
+ 'addr': '123.45.67.89',
+ 'OS-EXT-IPS:type': 'floating',
+ }, ],
+ '67890': [{
+ 'version': '6',
+ 'addr': '2001:123:5gf6:6789:a800:ff:dast:434d',
+ 'OS-EXT-IPS:type': 'fixed',
+ }, ],
+ }
+ attachments = [
+ {
+ 'network_id': '12345',
+ 'mac_address': 'a mac address',
+ 'id': 'an attachment id',
+ 'firewallProfile': 'DISABLED',
+ 'OS-EXT-IPS:type': 'floating',
+ 'ipv4': '123.45.67.89',
+ 'ipv6': '',
+ },
+ {
+ 'network_id': '67890',
+ 'mac_address': 'another mac address',
+ 'id': 'another attachment id',
+ 'firewallProfile': 'DISABLED',
+ 'OS-EXT-IPS:type': 'fixed',
+ 'ipv4': '',
+ 'ipv6': '2001:123:5gf6:6789:a800:ff:dast:434d',
+ },
+ ]
+ expected_addresses = {
+ '12345': [{
+ 'version': '4',
+ 'addr': '123.45.67.89',
+ 'OS-EXT-IPS:type': 'floating',
+ 'net_id': '12345',
+ 'OS-EXT-IPS-MAC:mac_addr': 'a mac address',
+ }, ],
+ '67890': [{
+ 'version': '6',
+ 'addr': '2001:123:5gf6:6789:a800:ff:dast:434d',
+ 'OS-EXT-IPS:type': 'fixed',
+ 'net_id': '67890',
+ 'OS-EXT-IPS-MAC:mac_addr': 'another mac address',
+ }, ],
+ }
+ compute._openstackify_addresses(addresses, attachments)
+ assert addresses == expected_addresses
+
+
+_response = {
+ 'addresses': 'some addresses', 'attachments': 'some attachments'
+}
+
+
+@patch('soi.compute._openstackify_addresses')
+@patch('soi.tests.fakes.DummyClass.get_from_response', return_value=_response)
+@patch('soi.tests.fakes.FakeReq.get_response', return_value='my response')
+def test_snf_get_server(gr, gfr, _oa):
+ """Test snf_get_server"""
+ cls, req = fakes.DummyClass(), fakes.FakeReq()
+ r = compute.snf_get_server(cls, req, 'my server id')
+ assert r == _response
+ assert req.environ == dict(
+ service_type='compute',
+ method_name='servers_get',
+ kwargs=dict(server_id='my server id'))
+ gr.assert_called_once_with(cls.app)
+ gfr.assert_called_once_with('my response', 'server', {})
+ _oa.assert_called_once_with(
+ _response['addresses'], _response['attachments'])
+
+
+@patch('soi.tests.fakes.DummyClass.get_from_response', return_value='g f r')
+@patch('soi.tests.fakes.FakeReq.get_response', return_value='my response')
+def test_snf_get_flavor(gr, gfr):
+ """Test snf_get_flavor"""
+ cls, req = fakes.DummyClass(), fakes.FakeReq()
+ r = compute.snf_get_flavor(cls, req, 'my flavor id')
+ assert r == 'g f r'
+ assert req.environ == dict(
+ service_type='compute',
+ method_name='flavors_get',
+ kwargs=dict(flavor_id='my flavor id'))
+ gr.assert_called_once_with(cls.app)
+ gfr.assert_called_once_with('my response', 'flavor', {})
+
+
+@patch('soi.tests.fakes.DummyClass.get_from_response', return_value='g f r')
+@patch('soi.tests.fakes.FakeReq.get_response', return_value='my response')
+def test_snf_get_image(gr, gfr):
+ """Test snf_get_image"""
+ cls, req = fakes.DummyClass(), fakes.FakeReq()
+ r = compute.snf_get_image(cls, req, 'my image id')
+ assert r == 'g f r'
+ assert req.environ == dict(
+ service_type='compute',
+ method_name='images_get',
+ kwargs=dict(image_id='my image id'))
+ gr.assert_called_once_with(cls.app)
+ gfr.assert_called_once_with('my response', 'image', {})
+
+
+@patch('soi.tests.fakes.DummyClass.get_from_response', return_value='g f r')
+@patch('soi.tests.fakes.FakeReq.get_response', return_value='my response')
+def test_snf_get_server_volume_links(gr, gfr):
+ """Test snf_get_server_volume_links"""
+ cls, req = fakes.DummyClass(), fakes.FakeReq()
+ r = compute.snf_get_server_volumes_link(cls, req, 'my server id')
+ assert r == 'g f r'
+ assert req.environ == dict(
+ service_type='compute',
+ method_name='volume_attachment_get',
+ kwargs=dict(server_id='my server id'))
+ gr.assert_called_once_with(cls.app)
+ gfr.assert_called_once_with('my response', 'volumeAttachments', [])
+
+
+def test__openstackify_net_attachments():
+ """Test _openstackify_net_attachments"""
+ input_ = [
+ {
+ 'network_id': '12345',
+ 'mac_address': 'a mac address',
+ 'id': 'an attachment id',
+ 'firewallProfile': 'DISABLED',
+ 'OS-EXT-IPS:type': 'floating',
+ 'ipv4': '123.45.67.89',
+ 'ipv6': '',
+ },
+ {
+ 'network_id': '67890',
+ 'mac_address': 'another mac address',
+ 'id': 'another attachment id',
+ 'firewallProfile': 'DISABLED',
+ 'OS-EXT-IPS:type': 'fixed',
+ 'ipv4': '',
+ 'ipv6': '2001:123:5gf6:6789:a800:ff:dast:434d',
+ },
+ ]
+ expected_output = [
+ {
+ 'network_id': '12345',
+ 'net_id': '12345',
+ 'mac_address': 'a mac address',
+ 'mac_addr': 'a mac address',
+ 'id': 'an attachment id',
+ 'port_id': 'an attachment id',
+ 'firewallProfile': 'DISABLED',
+ 'OS-EXT-IPS:type': 'floating',
+ 'ipv4': '123.45.67.89',
+ 'ipv6': '',
+ },
+ {
+ 'network_id': '67890',
+ 'net_id': '67890',
+ 'mac_address': 'another mac address',
+ 'mac_addr': 'another mac address',
+ 'id': 'another attachment id',
+ 'port_id': 'another attachment id',
+ 'firewallProfile': 'DISABLED',
+ 'OS-EXT-IPS:type': 'fixed',
+ 'ipv4': '',
+ 'ipv6': '2001:123:5gf6:6789:a800:ff:dast:434d',
+ 'fixed_ips': {
+ 'ip_address': '2001:123:5gf6:6789:a800:ff:dast:434d'},
+ },
+ ]
+ compute._openstackify_net_attachments(input_)
+ assert input_ == expected_output
+
+
+@patch('soi.compute._openstackify_net_attachments')
+@patch('soi.tests.fakes.DummyClass.get_from_response', return_value='g f r')
+@patch('soi.tests.fakes.FakeReq.get_response', return_value='my response')
+def test_snf_get_server_net_attachments(gr, gfr, _ona):
+ """Test snf_get_server_net_attachments"""
+ cls, req = fakes.DummyClass(), fakes.FakeReq()
+ r = compute.snf_get_server_net_attachments(cls, req, 'my server id')
+ assert r == 'g f r'
+ assert req.environ == dict(
+ service_type='compute',
+ method_name='servers_ips_get',
+ kwargs=dict(server_id='my server id'))
+ gr.assert_called_once_with(cls.app)
+ gfr.assert_called_once_with('my response', 'attachments', [])
+ _ona.assert_called_once_with('g f r')
+
+
+@patch('soi.compute._openstackify_addresses')
+@patch('soi.tests.fakes.DummyClass.get_from_response', return_value=_response)
+@patch('soi.tests.fakes.FakeReq.get_response', return_value='my response')
+def test_snf_create_server(gr, gfr, _oa):
+ """Test snf_create_server"""
+ cls, req = fakes.DummyClass(), fakes.FakeReq()
+ req.environ['HTTP_X_PROJECT_ID'] = 'a project id'
+ args = ('a name', 'an image', 'a flavor')
+ r = compute.snf_create_server(cls, req, *args)
+ assert r == _response
+ assert req.environ == dict(
+ HTTP_X_PROJECT_ID='a project id',
+ service_type='compute',
+ method_name='servers_post',
+ kwargs=dict(json_data=dict(server=dict(
+ name='a name', imageRef='an image', flavorRef='a flavor',
+ project='a project id'))))
+ gr.assert_called_once_with(cls.app)
+ gfr.assert_called_once_with('my response', 'server', {})
+ _oa.assert_called_once_with(
+ _response['addresses'], _response['attachments'])
+
+
+@patch('soi.tests.fakes.FakeReq.get_response')
+def test_snf_delete_server(gr):
+ """Test snf_delete_server"""
+ cls, req = fakes.DummyClass(), fakes.FakeReq()
+ compute.snf_delete_server(cls, req, 'my server id')
+ assert req.environ == dict(
+ service_type='compute',
+ method_name='servers_delete',
+ kwargs=dict(server_id='my server id'))
+ gr.assert_called_once_with(cls.app)
+
+
+def _test_snf_run_action(action, json_data, gr):
+ """used by "test_snf_run_action_* methods"""
+ cls, req = fakes.DummyClass(), fakes.FakeReq()
+ compute.snf_run_action(cls, req, action, 'my server id')
+ assert req.environ == dict(
+ service_type='compute',
+ method_name='servers_action_post',
+ kwargs=dict(server_id='my server id', json_data=json_data))
+ gr.assert_called_once_with(cls.app)
+
+
+@patch('soi.tests.fakes.FakeReq.get_response')
+def test_snf_run_action_start(gr):
+ """Test snf_run_action start"""
+ _test_snf_run_action('start', {'start': {}}, gr)
+
+
+@patch('soi.tests.fakes.FakeReq.get_response')
+def test_snf_run_action_stop(gr):
+ """Test snf_run_action stop"""
+ _test_snf_run_action('stop', {'shutdown': {}}, gr)
+
+
+@patch('soi.tests.fakes.FakeReq.get_response')
+def test_snf_run_action_restart(gr):
+ """Test snf_run_action restart"""
+ _test_snf_run_action('restart', {'reboot': {'type': 'SOFT'}}, gr)
+
+
+@patch('soi.tests.fakes.FakeReq.get_response')
+def test_snf_run_action_suspend(gr):
+ """Test snf_run_action suspend"""
+ try:
+ _test_snf_run_action('suspend', {}, gr)
+ except Exception as e:
+ from webob.exc import HTTPNotImplemented
+ assert isinstance(e, HTTPNotImplemented)
diff --git a/soi/tests/unit/utils.py b/soi/tests/unit/utils.py
index e563ec55d2c7a0ccd86513633104df0b67ce2945..83f77ced9d9d73c17205737d73fb2b49fcfeebcf 100644
--- a/soi/tests/unit/utils.py
+++ b/soi/tests/unit/utils.py
@@ -14,6 +14,7 @@
from soi import utils
from mock import patch
+from soi.tests import fakes
def test_patch_class_methods():
@@ -38,34 +39,12 @@ def test_patch_class_methods():
assert client.an_other_method('arg1', 'arg2') == 'replace arg1 arg2'
-def test_empty_list_200():
+@patch('soi.tests.fakes.DummyClass.get_from_response', return_value='g f r')
+@patch('soi.tests.fakes.FakeReq.get_response', return_value='my response')
+def test_empty_list_200(gr, gfr):
"""Test the empty list method"""
- class FakeReq:
- """use it for testing"""
- environ = dict()
-
- def get_response(self, *args, **kwargs):
- """Don't do enything"""
-
- class DummyClass:
- """use it for testing"""
- def app(self, *args, **kwargs):
- """inner app"""
-
- def get_from_response(self, *args, **kwargs):
- """Don't do enything"""
-
- setattr(utils, 'FakeReq', FakeReq)
- setattr(utils, 'DummyClass', DummyClass)
-
- with patch(
- 'soi.utils.FakeReq.get_response',
- return_value='my response') as gr:
- with patch(
- 'soi.utils.DummyClass.get_from_response',
- return_value='get from response') as gfr:
- cls, req = DummyClass(), FakeReq()
- r = utils.empty_list_200(cls, req)
- assert r == 'get from response'
- gfr.assert_called_once_with('my response', 'empty list', [])
- gr.assert_called_once_with(cls.app)
+ cls, req = fakes.DummyClass(), fakes.FakeReq()
+ r = utils.empty_list_200(cls, req)
+ assert r == 'g f r'
+ gfr.assert_called_once_with('my response', 'empty list', [])
+ gr.assert_called_once_with(cls.app)