# vim: tabstop=4 shiftwidth=4 softtabstop=4

# Copyright 2010 OpenStack LLC.
# 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 json
import webob
import xml.dom.minidom as minidom

from nova.api.openstack import flavors
import nova.db.api
from nova import exception
from nova import test
from nova.tests.api.openstack import fakes
from nova import wsgi


def stub_flavor(flavorid, name, memory_mb="256", local_gb="10"):
    return {
        "flavorid": str(flavorid),
        "name": name,
        "memory_mb": memory_mb,
        "local_gb": local_gb,
    }


def return_instance_type_by_flavor_id(context, flavorid):
    return stub_flavor(flavorid, "flavor %s" % (flavorid,))


def return_instance_types(context, num=2):
    instance_types = {}
    for i in xrange(1, num + 1):
        name = "flavor %s" % (i,)
        instance_types[name] = stub_flavor(i, name)
    return instance_types


def return_instance_type_not_found(context, flavor_id):
    raise exception.InstanceTypeNotFound(flavor_id=flavor_id)


class FlavorsTest(test.TestCase):
    def setUp(self):
        super(FlavorsTest, self).setUp()
        fakes.stub_out_networking(self.stubs)
        fakes.stub_out_rate_limiting(self.stubs)
        self.stubs.Set(nova.db.api, "instance_type_get_all",
                       return_instance_types)
        self.stubs.Set(nova.db.api, "instance_type_get_by_flavor_id",
                       return_instance_type_by_flavor_id)

    def tearDown(self):
        self.stubs.UnsetAll()
        super(FlavorsTest, self).tearDown()

    def test_get_flavor_list_v1_0(self):
        req = webob.Request.blank('/v1.0/flavors')
        res = req.get_response(fakes.wsgi_app())
        self.assertEqual(res.status_int, 200)
        flavors = json.loads(res.body)["flavors"]
        expected = [
            {
                "id": "1",
                "name": "flavor 1",
            },
            {
                "id": "2",
                "name": "flavor 2",
            },
        ]
        self.assertEqual(flavors, expected)

    def test_get_empty_flavor_list_v1_0(self):
        def _return_empty(self):
            return {}
        self.stubs.Set(nova.db.api, "instance_type_get_all",
                       _return_empty)

        req = webob.Request.blank('/v1.0/flavors')
        res = req.get_response(fakes.wsgi_app())
        self.assertEqual(res.status_int, 200)
        flavors = json.loads(res.body)["flavors"]
        expected = []
        self.assertEqual(flavors, expected)

    def test_get_flavor_list_detail_v1_0(self):
        req = webob.Request.blank('/v1.0/flavors/detail')
        res = req.get_response(fakes.wsgi_app())
        self.assertEqual(res.status_int, 200)
        flavors = json.loads(res.body)["flavors"]
        expected = [
            {
                "id": "1",
                "name": "flavor 1",
                "ram": "256",
                "disk": "10",
            },
            {
                "id": "2",
                "name": "flavor 2",
                "ram": "256",
                "disk": "10",
            },
        ]
        self.assertEqual(flavors, expected)

    def test_get_flavor_by_id_v1_0(self):
        req = webob.Request.blank('/v1.0/flavors/12')
        res = req.get_response(fakes.wsgi_app())
        self.assertEqual(res.status_int, 200)
        flavor = json.loads(res.body)["flavor"]
        expected = {
            "id": "12",
            "name": "flavor 12",
            "ram": "256",
            "disk": "10",
        }
        self.assertEqual(flavor, expected)

    def test_get_flavor_by_invalid_id(self):
        self.stubs.Set(nova.db.api, "instance_type_get_by_flavor_id",
                       return_instance_type_not_found)
        req = webob.Request.blank('/v1.0/flavors/asdf')
        res = req.get_response(fakes.wsgi_app())
        self.assertEqual(res.status_int, 404)

    def test_get_flavor_by_id_v1_1(self):
        req = webob.Request.blank('/v1.1/flavors/12')
        req.environ['api.version'] = '1.1'
        res = req.get_response(fakes.wsgi_app())
        self.assertEqual(res.status_int, 200)
        flavor = json.loads(res.body)
        expected = {
            "flavor": {
                "id": "12",
                "name": "flavor 12",
                "ram": "256",
                "disk": "10",
                "links": [
                    {
                        "rel": "self",
                        "href": "http://localhost/v1.1/flavors/12",
                    },
                    {
                        "rel": "bookmark",
                        "href": "http://localhost/flavors/12",
                    },
                ],
            },
        }
        self.assertEqual(flavor, expected)

    def test_get_flavor_list_v1_1(self):
        req = webob.Request.blank('/v1.1/flavors')
        req.environ['api.version'] = '1.1'
        res = req.get_response(fakes.wsgi_app())
        self.assertEqual(res.status_int, 200)
        flavor = json.loads(res.body)
        expected = {
            "flavors": [
                {
                    "id": "1",
                    "name": "flavor 1",
                    "links": [
                        {
                            "rel": "self",
                            "href": "http://localhost/v1.1/flavors/1",
                        },
                        {
                            "rel": "bookmark",
                            "href": "http://localhost/flavors/1",
                        },
                    ],
                },
                {
                    "id": "2",
                    "name": "flavor 2",
                    "links": [
                        {
                            "rel": "self",
                            "href": "http://localhost/v1.1/flavors/2",
                        },
                        {
                            "rel": "bookmark",
                            "href": "http://localhost/flavors/2",
                        },
                    ],
                },
            ],
        }
        self.assertEqual(flavor, expected)

    def test_get_flavor_list_detail_v1_1(self):
        req = webob.Request.blank('/v1.1/flavors/detail')
        req.environ['api.version'] = '1.1'
        res = req.get_response(fakes.wsgi_app())
        self.assertEqual(res.status_int, 200)
        flavor = json.loads(res.body)
        expected = {
            "flavors": [
                {
                    "id": "1",
                    "name": "flavor 1",
                    "ram": "256",
                    "disk": "10",
                    "links": [
                        {
                            "rel": "self",
                            "href": "http://localhost/v1.1/flavors/1",
                        },
                        {
                            "rel": "bookmark",
                            "href": "http://localhost/flavors/1",
                        },
                    ],
                },
                {
                    "id": "2",
                    "name": "flavor 2",
                    "ram": "256",
                    "disk": "10",
                    "links": [
                        {
                            "rel": "self",
                            "href": "http://localhost/v1.1/flavors/2",
                        },
                        {
                            "rel": "bookmark",
                            "href": "http://localhost/flavors/2",
                        },
                    ],
                },
            ],
        }
        self.assertEqual(flavor, expected)

    def test_get_empty_flavor_list_v1_1(self):
        def _return_empty(self):
            return {}
        self.stubs.Set(nova.db.api, "instance_type_get_all", _return_empty)

        req = webob.Request.blank('/v1.1/flavors')
        res = req.get_response(fakes.wsgi_app())
        self.assertEqual(res.status_int, 200)
        flavors = json.loads(res.body)["flavors"]
        expected = []
        self.assertEqual(flavors, expected)


class FlavorsXMLSerializationTest(test.TestCase):

    def test_show(self):
        serializer = flavors.FlavorXMLSerializer()

        input = {
            "flavor": {
                "id": "12",
                "name": "asdf",
                "ram": "256",
                "disk": "10",
                "links": [
                    {
                        "rel": "self",
                        "href": "http://localhost/v1.1/flavors/12",
                    },
                    {
                        "rel": "bookmark",
                        "href": "http://localhost/flavors/12",
                    },
                ],
            },
        }

        output = serializer.serialize(input, 'show')
        actual = minidom.parseString(output.replace("  ", ""))

        expected = minidom.parseString("""
        <flavor xmlns="http://docs.openstack.org/compute/api/v1.1"
                xmlns:atom="http://www.w3.org/2005/Atom"
                id="12"
                name="asdf"
                ram="256"
                disk="10">
            <atom:link href="http://localhost/v1.1/flavors/12" rel="self"/>
            <atom:link href="http://localhost/flavors/12" rel="bookmark"/>
        </flavor>
        """.replace("  ", ""))

        self.assertEqual(expected.toxml(), actual.toxml())

    def test_show_handles_integers(self):
        serializer = flavors.FlavorXMLSerializer()

        input = {
            "flavor": {
                "id": 12,
                "name": "asdf",
                "ram": 256,
                "disk": 10,
                "links": [
                    {
                        "rel": "self",
                        "href": "http://localhost/v1.1/flavors/12",
                    },
                    {
                        "rel": "bookmark",
                        "href": "http://localhost/flavors/12",
                    },
                ],
            },
        }

        output = serializer.serialize(input, 'show')
        actual = minidom.parseString(output.replace("  ", ""))

        expected = minidom.parseString("""
        <flavor xmlns="http://docs.openstack.org/compute/api/v1.1"
                xmlns:atom="http://www.w3.org/2005/Atom"
                id="12"
                name="asdf"
                ram="256"
                disk="10">
            <atom:link href="http://localhost/v1.1/flavors/12" rel="self"/>
            <atom:link href="http://localhost/flavors/12" rel="bookmark"/>
        </flavor>
        """.replace("  ", ""))

        self.assertEqual(expected.toxml(), actual.toxml())

    def test_detail(self):
        serializer = flavors.FlavorXMLSerializer()

        input = {
            "flavors": [
                {
                    "id": "23",
                    "name": "flavor 23",
                    "ram": "512",
                    "disk": "20",
                    "links": [
                        {
                            "rel": "self",
                            "href": "http://localhost/v1.1/flavors/23",
                        },
                        {
                            "rel": "bookmark",
                            "href": "http://localhost/flavors/23",
                        },
                    ],
                },        {
                    "id": "13",
                    "name": "flavor 13",
                    "ram": "256",
                    "disk": "10",
                    "links": [
                        {
                            "rel": "self",
                            "href": "http://localhost/v1.1/flavors/13",
                        },
                        {
                            "rel": "bookmark",
                            "href": "http://localhost/flavors/13",
                        },
                    ],
                },
            ],
        }

        output = serializer.serialize(input, 'detail')
        actual = minidom.parseString(output.replace("  ", ""))

        expected = minidom.parseString("""
        <flavors xmlns="http://docs.openstack.org/compute/api/v1.1"
                 xmlns:atom="http://www.w3.org/2005/Atom">
            <flavor id="23"
                    name="flavor 23"
                    ram="512"
                    disk="20">
                <atom:link href="http://localhost/v1.1/flavors/23" rel="self"/>
                <atom:link href="http://localhost/flavors/23" rel="bookmark"/>
            </flavor>
            <flavor id="13"
                    name="flavor 13"
                    ram="256"
                    disk="10">
                <atom:link href="http://localhost/v1.1/flavors/13" rel="self"/>
                <atom:link href="http://localhost/flavors/13" rel="bookmark"/>
            </flavor>
        </flavors>
        """.replace("  ", "") % locals())

        self.assertEqual(expected.toxml(), actual.toxml())

    def test_index(self):
        serializer = flavors.FlavorXMLSerializer()

        input = {
            "flavors": [
                {
                    "id": "23",
                    "name": "flavor 23",
                    "ram": "512",
                    "disk": "20",
                    "links": [
                        {
                            "rel": "self",
                            "href": "http://localhost/v1.1/flavors/23",
                        },
                        {
                            "rel": "bookmark",
                            "href": "http://localhost/flavors/23",
                        },
                    ],
                },        {
                    "id": "13",
                    "name": "flavor 13",
                    "ram": "256",
                    "disk": "10",
                    "links": [
                        {
                            "rel": "self",
                            "href": "http://localhost/v1.1/flavors/13",
                        },
                        {
                            "rel": "bookmark",
                            "href": "http://localhost/flavors/13",
                        },
                    ],
                },
            ],
        }

        output = serializer.serialize(input, 'index')
        actual = minidom.parseString(output.replace("  ", ""))

        expected = minidom.parseString("""
        <flavors xmlns="http://docs.openstack.org/compute/api/v1.1"
                 xmlns:atom="http://www.w3.org/2005/Atom">
            <flavor id="23" name="flavor 23">
                <atom:link href="http://localhost/v1.1/flavors/23" rel="self"/>
                <atom:link href="http://localhost/flavors/23" rel="bookmark"/>
            </flavor>
            <flavor id="13" name="flavor 13">
                <atom:link href="http://localhost/v1.1/flavors/13" rel="self"/>
                <atom:link href="http://localhost/flavors/13" rel="bookmark"/>
            </flavor>
        </flavors>
        """.replace("  ", "") % locals())

        self.assertEqual(expected.toxml(), actual.toxml())

    def test_index_empty(self):
        serializer = flavors.FlavorXMLSerializer()

        input = {
            "flavors": [],
        }

        output = serializer.serialize(input, 'index')
        actual = minidom.parseString(output.replace("  ", ""))

        expected = minidom.parseString("""
        <flavors xmlns="http://docs.openstack.org/compute/api/v1.1"
                 xmlns:atom="http://www.w3.org/2005/Atom" />
        """.replace("  ", "") % locals())

        self.assertEqual(expected.toxml(), actual.toxml())
