ARIA multivim plugin initial checkin

Change-Id: I3a24ab6fc5ba54466bfecaf596a13b8907248ae8
Issue-id: SO-77
Signed-off-by: DeWayne Filppi <dewayne@gigaspaces.com>
diff --git a/aria/multivim-plugin/glance_plugin/tests/resources/test-image-start.yaml b/aria/multivim-plugin/glance_plugin/tests/resources/test-image-start.yaml
new file mode 100644
index 0000000..12c9aa7
--- /dev/null
+++ b/aria/multivim-plugin/glance_plugin/tests/resources/test-image-start.yaml
@@ -0,0 +1,30 @@
+
+tosca_definitions_version: cloudify_dsl_1_3
+
+imports:
+  - https://raw.githubusercontent.com/cloudify-cosmo/cloudify-manager/4.1/resources/rest-service/cloudify/types/types.yaml
+  - plugin.yaml
+
+inputs:
+  use_password:
+    type: boolean
+    default: false
+
+node_templates:
+  image:
+    type: cloudify.openstack.nodes.Image
+    properties:
+      image:
+        disk_format: test_format
+        container_format: test_format
+        data: test_path
+      openstack_config:
+        username: aaa
+        password: aaa
+        tenant_name: aaa
+        auth_url: aaa
+    interfaces:
+      cloudify.interfaces.lifecycle:
+        start:
+          inputs:
+            start_retry_interval: 1
diff --git a/aria/multivim-plugin/glance_plugin/tests/test.py b/aria/multivim-plugin/glance_plugin/tests/test.py
new file mode 100644
index 0000000..4a88cba
--- /dev/null
+++ b/aria/multivim-plugin/glance_plugin/tests/test.py
@@ -0,0 +1,148 @@
+#########
+# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved
+#
+# 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 mock
+import os
+import tempfile
+import unittest
+
+import glance_plugin
+from glance_plugin import image
+
+from cloudify.mocks import MockCloudifyContext
+from cloudify.test_utils import workflow_test
+from cloudify.exceptions import NonRecoverableError
+
+
+def ctx_mock(image_dict):
+    return MockCloudifyContext(
+        node_id='d',
+        properties=image_dict)
+
+
+class TestCheckImage(unittest.TestCase):
+
+    @mock.patch('glance_plugin.image.ctx',
+                ctx_mock({'image': {}}))
+    def test_check_image_no_file_no_url(self):
+        # Test if it throws exception no file & no url
+        self.assertRaises(NonRecoverableError,
+                          image._validate_image)
+
+    @mock.patch('glance_plugin.image.ctx',
+                ctx_mock({'image_url': 'test-url', 'image': {'data': '.'}}))
+    def test_check_image_and_url(self):
+        # Test if it throws exception file & url
+        self.assertRaises(NonRecoverableError,
+                          image._validate_image)
+
+    @mock.patch('glance_plugin.image.ctx',
+                ctx_mock({'image_url': 'test-url', 'image': {}}))
+    def test_check_image_url(self):
+        # test if it passes no file & url
+        http_connection_mock = mock.MagicMock()
+        http_connection_mock.return_value.getresponse.return_value.status = 200
+        with mock.patch('httplib.HTTPConnection', http_connection_mock):
+            glance_plugin.image._validate_image()
+
+    def test_check_image_file(self):
+        # test if it passes file & no url
+        image_file_path = tempfile.mkstemp()[1]
+        with mock.patch('glance_plugin.image.ctx',
+                        ctx_mock({'image': {'data': image_file_path}})):
+            glance_plugin.image._validate_image()
+
+    @mock.patch('glance_plugin.image.ctx',
+                ctx_mock({'image': {'data': '/test/path'}}))
+    # test when open file throws IO error
+    def test_check_image_bad_file(self):
+        open_name = '%s.open' % __name__
+        with mock.patch(open_name, create=True) as mock_open:
+            mock_open.side_effect = [mock_open(read_data='Data').return_value]
+            self.assertRaises(NonRecoverableError,
+                              glance_plugin.image._validate_image)
+
+    @mock.patch('glance_plugin.image.ctx',
+                ctx_mock({'image_url': '?', 'image': {}}))
+    # test when bad url
+    def test_check_image_bad_url(self):
+        http_connection_mock = mock.MagicMock()
+        http_connection_mock.return_value.getresponse.return_value.status = 400
+        with mock.patch('httplib.HTTPConnection', http_connection_mock):
+            self.assertRaises(NonRecoverableError,
+                              glance_plugin.image._validate_image)
+
+
+class TestValidateProperties(unittest.TestCase):
+
+    @mock.patch('glance_plugin.image.ctx',
+                ctx_mock({'image': {'container_format': 'bare'}}))
+    def test_check_image_container_format_no_disk_format(self):
+        # Test if it throws exception no file & no url
+        self.assertRaises(NonRecoverableError,
+                          image._validate_image_dictionary)
+
+    @mock.patch('glance_plugin.image.ctx',
+                ctx_mock({'image': {'disk_format': 'qcow2'}}))
+    def test_check_image_no_container_format_disk_format(self):
+        # Test if it throws exception no container_format & disk_format
+        self.assertRaises(NonRecoverableError,
+                          image._validate_image_dictionary)
+
+    @mock.patch('glance_plugin.image.ctx',
+                ctx_mock({'image': {}}))
+    def test_check_image_no_container_format_no_disk_format(self):
+        # Test if it throws exception no container_format & no disk_format
+        self.assertRaises(NonRecoverableError,
+                          image._validate_image_dictionary)
+
+    @mock.patch('glance_plugin.image.ctx',
+                ctx_mock(
+                    {'image':
+                        {'container_format': 'bare',
+                         'disk_format': 'qcow2'}}))
+    def test_check_image_container_format_disk_format(self):
+        # Test if it do not throw exception container_format & disk_format
+        image._validate_image_dictionary()
+
+
+class TestStartImage(unittest.TestCase):
+    blueprint_path = os.path.join('resources',
+                                  'test-image-start.yaml')
+
+    @mock.patch('glance_plugin.image.create')
+    @workflow_test(blueprint_path, copy_plugin_yaml=True)
+    def test_image_lifecycle_start(self, cfy_local, *_):
+        test_vars = {
+            'counter': 0,
+            'image': mock.MagicMock()
+        }
+
+        def _mock_get_image_by_ctx(*_):
+            i = test_vars['image']
+            if test_vars['counter'] == 0:
+                i.status = 'different image status'
+            else:
+                i.status = glance_plugin.image.IMAGE_STATUS_ACTIVE
+            test_vars['counter'] += 1
+            return i
+
+        with mock.patch('openstack_plugin_common.GlanceClient'):
+            with mock.patch('glance_plugin.image._get_image_by_ctx',
+                            side_effect=_mock_get_image_by_ctx):
+                cfy_local.execute('install', task_retries=3)
+
+        self.assertEqual(2, test_vars['counter'])
+        self.assertEqual(0, test_vars['image'].start.call_count)