# Copyright 2012 OpenStack Foundation.
# 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 testtools

from glanceclient.tests import utils
from glanceclient.v2 import metadefs

NAMESPACE1 = 'Namespace1'
PROPERTY1 = 'Property1'
PROPERTY2 = 'Property2'
PROPERTYNEW = 'PropertyNew'

data_fixtures = {
    "/v2/metadefs/namespaces/%s/properties" % NAMESPACE1: {
        "GET": (
            {},
            {
                "properties": {
                    PROPERTY1: {
                        "default": "1",
                        "type": "integer",
                        "description": "Number of cores.",
                        "title": "cores"
                    },
                    PROPERTY2: {
                        "items": {
                            "enum": [
                                "Intel",
                                "AMD"
                            ],
                            "type": "string"
                        },
                        "type": "array",
                        "description": "Specifies the CPU manufacturer.",
                        "title": "Vendor"
                    },
                }
            }
        ),
        "POST": (
            {},
            {
                "items": {
                    "enum": [
                        "Intel",
                        "AMD"
                    ],
                    "type": "string"
                },
                "type": "array",
                "description": "UPDATED_DESCRIPTION",
                "title": "Vendor",
                "name": PROPERTYNEW
            }
        ),
        "DELETE": (
            {},
            {}
        )
    },
    "/v2/metadefs/namespaces/%s/properties/%s" % (NAMESPACE1, PROPERTY1): {
        "GET": (
            {},
            {
                "items": {
                    "enum": [
                        "Intel",
                        "AMD"
                    ],
                    "type": "string"
                },
                "type": "array",
                "description": "Specifies the CPU manufacturer.",
                "title": "Vendor"
            }
        ),
        "PUT": (
            {},
            {
                "items": {
                    "enum": [
                        "Intel",
                        "AMD"
                    ],
                    "type": "string"
                },
                "type": "array",
                "description": "UPDATED_DESCRIPTION",
                "title": "Vendor"
            }
        ),
        "DELETE": (
            {},
            {}
        )
    }
}

schema_fixtures = {
    "metadefs/property": {
        "GET": (
            {},
            {
                "additionalProperties": False,
                "definitions": {
                    "positiveIntegerDefault0": {
                        "allOf": [
                            {
                                "$ref": "#/definitions/positiveInteger"
                            },
                            {
                                "default": 0
                            }
                        ]
                    },
                    "stringArray": {
                        "minItems": 1,
                        "items": {
                            "type": "string"
                        },
                        "uniqueItems": True,
                        "type": "array"
                    },
                    "positiveInteger": {
                        "minimum": 0,
                        "type": "integer"
                    }
                },
                "required": [
                    "name",
                    "title",
                    "type"
                ],
                "name": "property",
                "properties": {
                    "description": {
                        "type": "string"
                    },
                    "minLength": {
                        "$ref": "#/definitions/positiveIntegerDefault0"
                    },
                    "enum": {
                        "type": "array"
                    },
                    "minimum": {
                        "type": "number"
                    },
                    "maxItems": {
                        "$ref": "#/definitions/positiveInteger"
                    },
                    "maxLength": {
                        "$ref": "#/definitions/positiveInteger"
                    },
                    "uniqueItems": {
                        "default": False,
                        "type": "boolean"
                    },
                    "additionalItems": {
                        "type": "boolean"
                    },
                    "name": {
                        "type": "string"
                    },
                    "title": {
                        "type": "string"
                    },
                    "default": {},
                    "pattern": {
                        "type": "string",
                        "format": "regex"
                    },
                    "required": {
                        "$ref": "#/definitions/stringArray"
                    },
                    "maximum": {
                        "type": "number"
                    },
                    "minItems": {
                        "$ref": "#/definitions/positiveIntegerDefault0"
                    },
                    "readonly": {
                        "type": "boolean"
                    },
                    "items": {
                        "type": "object",
                        "properties": {
                            "enum": {
                                "type": "array"
                            },
                            "type": {
                                "enum": [
                                    "array",
                                    "boolean",
                                    "integer",
                                    "number",
                                    "object",
                                    "string",
                                    "null"
                                ],
                                "type": "string"
                            }
                        }
                    },
                    "type": {
                        "enum": [
                            "array",
                            "boolean",
                            "integer",
                            "number",
                            "object",
                            "string",
                            "null"
                        ],
                        "type": "string"
                    }
                }
            }
        )
    }
}


class TestPropertyController(testtools.TestCase):
    def setUp(self):
        super(TestPropertyController, self).setUp()
        self.api = utils.FakeAPI(data_fixtures)
        self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
        self.controller = metadefs.PropertyController(self.api,
                                                      self.schema_api)

    def test_list_property(self):
        properties = list(self.controller.list(NAMESPACE1))

        actual = [prop.name for prop in properties]
        self.assertEqual(sorted([PROPERTY1, PROPERTY2]), sorted(actual))

    def test_get_property(self):
        prop = self.controller.get(NAMESPACE1, PROPERTY1)
        self.assertEqual(PROPERTY1, prop.name)

    def test_create_property(self):
        properties = {
            'name': PROPERTYNEW,
            'title': 'TITLE',
            'type': 'string'
        }
        obj = self.controller.create(NAMESPACE1, **properties)
        self.assertEqual(PROPERTYNEW, obj.name)

    def test_create_property_invalid_property(self):
        properties = {
            'namespace': NAMESPACE1
        }
        self.assertRaises(TypeError, self.controller.create, **properties)

    def test_update_property(self):
        properties = {
            'description': 'UPDATED_DESCRIPTION'
        }
        prop = self.controller.update(NAMESPACE1, PROPERTY1, **properties)
        self.assertEqual(PROPERTY1, prop.name)

    def test_update_property_invalid_property(self):
        properties = {
            'type': 'INVALID'
        }
        self.assertRaises(TypeError, self.controller.update, NAMESPACE1,
                          PROPERTY1, **properties)

    def test_update_property_disallowed_fields(self):
        properties = {
            'description': 'UPDATED_DESCRIPTION'
        }
        self.controller.update(NAMESPACE1, PROPERTY1, **properties)
        actual = self.api.calls
        _disallowed_fields = ['created_at', 'updated_at']
        for key in actual[1][3]:
            self.assertNotIn(key, _disallowed_fields)

    def test_delete_property(self):
        self.controller.delete(NAMESPACE1, PROPERTY1)
        expect = [
            ('DELETE',
             '/v2/metadefs/namespaces/%s/properties/%s' % (NAMESPACE1,
                                                           PROPERTY1),
             {},
             None)]
        self.assertEqual(expect, self.api.calls)

    def test_delete_all_properties(self):
        self.controller.delete_all(NAMESPACE1)
        expect = [
            ('DELETE',
             '/v2/metadefs/namespaces/%s/properties' % NAMESPACE1,
             {},
             None)]
        self.assertEqual(expect, self.api.calls)
