#    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 datetime
import mock

from oslo_utils import timeutils
from oslo_utils import uuidutils

from esi_leap.common import exception as e
from esi_leap.common import statuses
from esi_leap.db.sqlalchemy import api
import esi_leap.tests.base as base

now = datetime.datetime(2016, 7, 16, 19, 20, 30)

test_offer_1 = dict(
    uuid="11111",
    project_id="0wn3r",
    name="o1",
    resource_uuid="1111",
    resource_type="dummy_node",
    start_time=now,
    end_time=now + datetime.timedelta(days=100),
    properties={"foo": "bar"},
    status=statuses.AVAILABLE,
)

test_offer_2 = dict(
    uuid="22222",
    project_id="0wn3r",
    lessee_id="12345",
    name="o1",
    resource_uuid="1111",
    resource_type="dummy_node",
    start_time=now + datetime.timedelta(days=25),
    end_time=now + datetime.timedelta(days=100),
    properties={"foo": "bar"},
    status=statuses.AVAILABLE,
)

test_offer_3 = dict(
    uuid="33333",
    project_id="0wn3r_2",
    lessee_id="67890",
    name="o1",
    resource_uuid="1111",
    resource_type="dummy_node",
    start_time=now + datetime.timedelta(days=50),
    end_time=now + datetime.timedelta(days=100),
    properties={"foo": "bar"},
    status=statuses.AVAILABLE,
)

test_offer_4 = dict(
    uuid="44444",
    project_id="0wn3r_2",
    lessee_id="ABCDE",
    name="o2",
    resource_uuid="1111",
    resource_type="dummy_node",
    start_time=now + datetime.timedelta(days=75),
    end_time=now + datetime.timedelta(days=100),
    properties={"foo": "bar"},
    status=statuses.AVAILABLE,
)

test_offer_5 = dict(
    uuid="55555",
    project_id="12345",
    lessee_id="ABCDE",
    name="o2",
    resource_uuid="1111",
    resource_type="dummy_node",
    start_time=now + datetime.timedelta(days=105),
    end_time=now + datetime.timedelta(days=150),
    properties={"foo": "bar"},
    status=statuses.AVAILABLE,
)

test_lease_1 = dict(
    uuid="11111",
    project_id="1e5533",
    owner_id="0wn3r",
    name="l1",
    resource_uuid="1111",
    resource_type="dummy_node",
    purpose="test_purpose",
    start_time=now + datetime.timedelta(days=10),
    end_time=now + datetime.timedelta(days=20),
    properties={},
    status=statuses.CREATED,
)

test_lease_2 = dict(
    uuid="22222",
    project_id="1e5533",
    owner_id="0wn3r",
    name="l1",
    resource_uuid="1111",
    resource_type="dummy_node",
    purpose="test_purpose",
    start_time=now + datetime.timedelta(days=20),
    end_time=now + datetime.timedelta(days=30),
    properties={},
    status=statuses.CREATED,
)

test_lease_3 = dict(
    uuid="33333",
    project_id="1e5533_2",
    owner_id="0wn3r_2",
    name="l1",
    resource_uuid="1111",
    resource_type="dummy_node",
    purpose="test_purpose",
    start_time=now + datetime.timedelta(days=50),
    end_time=now + datetime.timedelta(days=60),
    properties={},
    status=statuses.ACTIVE,
)

test_lease_4 = dict(
    uuid="44444",
    project_id="1e5533_2",
    owner_id="0wn3r_2",
    name="l4",
    resource_uuid="1111",
    resource_type="dummy_node",
    purpose="test_purpose",
    start_time=now + datetime.timedelta(days=85),
    end_time=now + datetime.timedelta(days=90),
    properties={},
    status=statuses.DELETED,
)

test_lease_5 = dict(
    project_id="0wn3r",
    owner_id="0wn3r_2",
    name="l5",
    resource_uuid="1111",
    resource_type="dummy_node",
    purpose="test_purpose",
    start_time=now + datetime.timedelta(days=90),
    end_time=now + datetime.timedelta(days=100),
    uuid="55555",
    properties={},
    status=statuses.EXPIRED,
)

test_lease_6 = dict(
    project_id="0wn3r",
    owner_id="0wn3r_2",
    name="l6",
    resource_uuid="2222",
    resource_type="dummy_node",
    purpose="test_purpose",
    start_time=now + datetime.timedelta(days=5),
    end_time=now + datetime.timedelta(days=30),
    uuid="6666",
    properties={},
    status=statuses.EXPIRED,
)

test_lease_7 = dict(
    uuid="77777",
    project_id="1e5533_2",
    owner_id="0wn3r_2",
    name="l1",
    resource_uuid="1111",
    resource_type="dummy_node",
    purpose="test_purpose",
    start_time=now - datetime.timedelta(days=10),
    end_time=now + datetime.timedelta(days=10),
    properties={},
    status=statuses.ACTIVE,
)

test_event_1 = dict(
    id=1,
    event_type="fake:event:start",
    event_time=now - datetime.timedelta(days=20),
    object_type="lease",
    object_uuid="11111",
    resource_type="dummy_node",
    resource_uuid="1111",
    lessee_id="1e5533",
    owner_id="0wn3r",
)

test_event_2 = dict(
    id=2,
    event_type="fake:event:end",
    event_time=now - datetime.timedelta(days=10),
    object_type="lease",
    object_uuid="11111",
    resource_type="dummy_node",
    resource_uuid="1111",
    lessee_id="1e5533",
    owner_id="0wn3r",
)

test_event_3 = dict(
    id=3,
    event_type="fake:event:start",
    event_time=now - datetime.timedelta(days=20),
    object_type="lease",
    object_uuid="22222",
    resource_type="dummy_node",
    resource_uuid="2222",
    lessee_id="1e5533",
    owner_id="0wn3r2",
)

test_cat_1 = dict(
    id=1,
    node_uuid="test-node-1",
    token_hash="test-hash-1",
    expires=timeutils.utcnow_ts() - 10000,
)

test_cat_2 = dict(
    id=2,
    node_uuid="test-node-2",
    token_hash="test-hash-2",
    expires=timeutils.utcnow_ts() + 10000,
)


class TestOfferAPI(base.DBTestCase):
    def test_offer_create(self):
        offer = api.offer_create(test_offer_1)
        o = api.offer_get_all({}).all()
        assert len(o) == 1
        assert o[0].to_dict() == offer.to_dict()

    def test_offer_verify_availability(self):
        offer = api.offer_create(test_offer_1)

        test_lease_1["offer_uuid"] = offer.uuid
        test_lease_2["offer_uuid"] = offer.uuid
        test_lease_3["offer_uuid"] = offer.uuid

        api.lease_create(test_lease_1)
        api.lease_create(test_lease_2)
        api.lease_create(test_lease_3)

        start = now + datetime.timedelta(days=35)
        end = now + datetime.timedelta(days=40)
        api.offer_verify_availability(offer, start, end)

        start = now + datetime.timedelta(days=5)
        end = now + datetime.timedelta(days=10)
        api.offer_verify_availability(offer, start, end)

        start = now
        end = now + datetime.timedelta(days=10)
        api.offer_verify_availability(offer, start, end)

        start = now + datetime.timedelta(days=90)
        end = now + datetime.timedelta(days=100)
        api.offer_verify_availability(offer, start, end)

        start = now + datetime.timedelta(days=60)
        end = now + datetime.timedelta(days=100)
        api.offer_verify_availability(offer, start, end)

        start = now + datetime.timedelta(days=30)
        end = now + datetime.timedelta(days=50)
        api.offer_verify_availability(offer, start, end)

        start = now + datetime.timedelta(days=15)
        end = now + datetime.timedelta(days=16)
        self.assertRaises(
            e.OfferNoTimeAvailabilities,
            api.offer_verify_availability,
            offer,
            start,
            end,
        )

        start = now + datetime.timedelta(days=45)
        end = now + datetime.timedelta(days=55)
        self.assertRaises(
            e.OfferNoTimeAvailabilities,
            api.offer_verify_availability,
            offer,
            start,
            end,
        )

        start = now + datetime.timedelta(days=55)
        end = now + datetime.timedelta(days=65)
        self.assertRaises(
            e.OfferNoTimeAvailabilities,
            api.offer_verify_availability,
            offer,
            start,
            end,
        )

        start = now + datetime.timedelta(days=50)
        end = now + datetime.timedelta(days=65)
        self.assertRaises(
            e.OfferNoTimeAvailabilities,
            api.offer_verify_availability,
            offer,
            start,
            end,
        )

        start = now + datetime.timedelta(days=45)
        end = now + datetime.timedelta(days=60)
        self.assertRaises(
            e.OfferNoTimeAvailabilities,
            api.offer_verify_availability,
            offer,
            start,
            end,
        )

        start = now + datetime.timedelta(days=90)
        end = now + datetime.timedelta(days=105)
        self.assertRaises(
            e.OfferNoTimeAvailabilities,
            api.offer_verify_availability,
            offer,
            start,
            end,
        )

        start = now + datetime.timedelta(days=100)
        end = now + datetime.timedelta(days=105)
        self.assertRaises(
            e.OfferNoTimeAvailabilities,
            api.offer_verify_availability,
            offer,
            start,
            end,
        )

        start = now + datetime.timedelta(days=105)
        end = now + datetime.timedelta(days=110)
        self.assertRaises(
            e.OfferNoTimeAvailabilities,
            api.offer_verify_availability,
            offer,
            start,
            end,
        )

        start = now - datetime.timedelta(days=1)
        end = now + datetime.timedelta(days=5)
        self.assertRaises(
            e.OfferNoTimeAvailabilities,
            api.offer_verify_availability,
            offer,
            start,
            end,
        )

        start = now - datetime.timedelta(days=1)
        end = now
        self.assertRaises(
            e.OfferNoTimeAvailabilities,
            api.offer_verify_availability,
            offer,
            start,
            end,
        )

        start = now - datetime.timedelta(days=10)
        end = now - datetime.timedelta(days=5)
        self.assertRaises(
            e.OfferNoTimeAvailabilities,
            api.offer_verify_availability,
            offer,
            start,
            end,
        )

        start = now + datetime.timedelta(days=45)
        end = now + datetime.timedelta(days=55)
        self.assertRaises(
            e.OfferNoTimeAvailabilities,
            api.offer_verify_availability,
            offer,
            start,
            end,
        )

        test_lease_4["offer_uuid"] = offer.uuid
        api.lease_create(test_lease_4)
        start = now + datetime.timedelta(days=86)
        end = now + datetime.timedelta(days=87)
        api.offer_verify_availability(offer, start, end)

    def test_offer_get_conflict_times(self):
        o1 = api.offer_create(test_offer_1)
        self.assertEqual(api.offer_get_conflict_times(o1), [])
        test_lease_3["offer_uuid"] = o1.uuid
        test_lease_4["offer_uuid"] = o1.uuid
        test_lease_5["offer_uuid"] = o1.uuid
        api.lease_create(test_lease_3)
        api.lease_create(test_lease_4)
        api.lease_create(test_lease_5)
        self.assertEqual(
            api.offer_get_conflict_times(o1),
            [(now + datetime.timedelta(days=50), now + datetime.timedelta(days=60))],
        )

    def test_offer_get_next_lease_start_time(self):
        o1 = api.offer_create(test_offer_1)
        self.assertEqual(
            api.offer_get_next_lease_start_time(
                o1.uuid,
                o1.start_time,
            ),
            None,
        )
        test_lease_3["offer_uuid"] = o1.uuid
        api.lease_create(test_lease_3)
        test_lease_7["offer_uuid"] = o1.uuid
        api.lease_create(test_lease_7)
        self.assertEqual(
            api.offer_get_next_lease_start_time(o1.uuid, o1.start_time),
            (now + datetime.timedelta(days=50),),
        )

    def test_offer_get_by_uuid(self):
        o1 = api.offer_create(test_offer_1)
        res = api.offer_get_by_uuid(o1.uuid)
        self.assertEqual(o1.uuid, res.uuid)
        self.assertEqual(o1.project_id, res.project_id)
        self.assertEqual(o1.properties, res.properties)

    def test_offer_get_by_uuid_not_found(self):
        assert api.offer_get_by_uuid("some_uuid") is None

    def test_offer_get_by_name(self):
        o1 = api.offer_create(test_offer_1)
        o2 = api.offer_create(test_offer_2)
        o3 = api.offer_create(test_offer_3)
        api.offer_create(test_offer_4)

        res = api.offer_get_by_name("o1")
        assert len(res) == 3
        self.assertEqual(o1.uuid, res[0].uuid)
        self.assertEqual(o1.project_id, res[0].project_id)

        self.assertEqual(o2.uuid, res[1].uuid)
        self.assertEqual(o2.project_id, res[1].project_id)

        self.assertEqual(o3.uuid, res[2].uuid)
        self.assertEqual(o3.project_id, res[2].project_id)

    def test_offer_get_by_name_not_found(self):
        self.assertEqual(api.offer_get_by_name("some_name"), [])

    def test_offer_destroy(self):
        o1 = api.offer_create(test_offer_2)
        api.offer_destroy(o1.uuid)
        self.assertEqual(api.offer_get_by_uuid("offer_2"), None)

    def test_offer_destroy_not_found(self):
        self.assertEqual(api.offer_get_by_uuid("offer_4"), None)

    def test_offer_update(self):
        o1 = api.offer_create(test_offer_3)
        values = {
            "start_time": test_offer_2["start_time"],
            "end_time": test_offer_2["end_time"],
        }
        api.offer_update(o1.uuid, values)
        o1 = api.offer_get_by_uuid(o1.uuid)

        self.assertEqual(test_offer_2["start_time"], o1.start_time)
        self.assertEqual(test_offer_2["end_time"], o1.end_time)

    def test_offer_update_invalid_time(self):
        o1 = api.offer_create(test_offer_3)
        values = {"start_time": now + datetime.timedelta(days=101), "end_time": now}
        self.assertRaises(e.InvalidTimeRange, api.offer_update, o1.uuid, values)

    def test_offer_get_all(self):
        o1 = api.offer_create(test_offer_2)
        o2 = api.offer_create(test_offer_3)
        res = api.offer_get_all({})

        self.assertEqual(2, res.count())
        self.assertEqual(
            (o1.to_dict(), o2.to_dict()), (res[0].to_dict(), res[1].to_dict())
        )

    @mock.patch("esi_leap.common.keystone.get_parent_project_id_tree")
    def test_offer_get_all_lessee_filter(self, mock_gppit):
        mock_gppit.return_value = ["12345", "67890"]

        o1 = api.offer_create(test_offer_1)
        o2 = api.offer_create(test_offer_2)
        o3 = api.offer_create(test_offer_3)
        api.offer_create(test_offer_4)
        o5 = api.offer_create(test_offer_5)
        res = api.offer_get_all({"lessee_id": "12345"})

        mock_gppit.assert_called_once_with("12345")
        self.assertEqual(4, res.count())
        self.assertEqual(
            (o1.to_dict(), o2.to_dict(), o3.to_dict(), o5.to_dict()),
            (res[0].to_dict(), res[1].to_dict(), res[2].to_dict(), res[3].to_dict()),
        )

    def test_offer_get_all_time_filter(self):
        o1 = api.offer_create(test_offer_1)
        o2 = api.offer_create(test_offer_2)
        api.offer_create(test_offer_3)
        api.offer_create(test_offer_4)
        api.offer_create(test_offer_5)
        res = api.offer_get_all(
            {
                "start_time": o1.start_time + datetime.timedelta(days=26),
                "end_time": o1.end_time + datetime.timedelta(days=-1),
            }
        )

        self.assertEqual(2, res.count())
        self.assertEqual(
            (o1.to_dict(), o2.to_dict()), (res[0].to_dict(), res[1].to_dict())
        )

    def test_offer_get_all_time_filter_within(self):
        o1 = api.offer_create(test_offer_1)
        o2 = api.offer_create(test_offer_2)
        o3 = api.offer_create(test_offer_3)
        o4 = api.offer_create(test_offer_4)
        api.offer_create(test_offer_5)
        res = api.offer_get_all(
            {
                "start_time": o1.end_time + datetime.timedelta(days=-2),
                "end_time": o2.end_time + datetime.timedelta(days=1),
                "time_filter_type": "within",
            }
        )

        self.assertEqual(4, res.count())
        self.assertEqual(
            (o1.to_dict(), o2.to_dict(), o3.to_dict(), o4.to_dict()),
            (res[0].to_dict(), res[1].to_dict(), res[2].to_dict(), res[3].to_dict()),
        )


class TestLeaseAPI(base.DBTestCase):
    def test_lease_get_by_uuid(self):
        o1 = api.offer_create(test_offer_2)
        test_lease_4["offer_uuid"] = o1.uuid
        l1 = api.lease_create(test_lease_4)
        res = api.lease_get_by_uuid(l1.uuid)
        self.assertEqual(l1.uuid, res.uuid)

    def test_lease_get_by_uuid_not_found(self):
        assert api.lease_get_by_uuid("some_uuid") is None

    def test_lease_get_by_name(self):
        o1 = api.offer_create(test_offer_1)
        o2 = api.offer_create(test_offer_2)
        o3 = api.offer_create(test_offer_3)
        o4 = api.offer_create(test_offer_4)
        test_lease_1["offer_uuid"] = o1.uuid
        test_lease_2["offer_uuid"] = o2.uuid
        test_lease_3["offer_uuid"] = o3.uuid
        test_lease_4["offer_uuid"] = o4.uuid
        l1 = api.lease_create(test_lease_1)
        l2 = api.lease_create(test_lease_2)
        l3 = api.lease_create(test_lease_3)
        api.lease_create(test_lease_4)
        res = api.lease_get_by_name("l1")
        assert len(res) == 3
        self.assertEqual(l1.uuid, res[0].uuid)
        self.assertEqual(l1.project_id, res[0].project_id)

        self.assertEqual(l2.uuid, res[1].uuid)
        self.assertEqual(l2.project_id, res[1].project_id)

        self.assertEqual(l3.uuid, res[2].uuid)
        self.assertEqual(l3.project_id, res[2].project_id)

    def test_lease_get_by_name_not_found(self):
        self.assertEqual(api.lease_get_by_name("some_name"), [])

    def test_lease_get_all(self):
        api.lease_create(test_lease_1)
        api.lease_create(test_lease_2)

        res = api.lease_get_all({})
        res_uuids = [res_lease.to_dict()["uuid"] for res_lease in res]

        self.assertEqual(2, res.count())
        self.assertIn(test_lease_1["uuid"], res_uuids)
        self.assertIn(test_lease_2["uuid"], res_uuids)

    def test_lease_get_all_filter_by_status(self):
        api.lease_create(test_lease_1)
        api.lease_create(test_lease_2)
        api.lease_create(test_lease_3)
        api.lease_create(test_lease_4)
        api.lease_create(test_lease_5)

        res = api.lease_get_all({"status": [statuses.CREATED, statuses.ACTIVE]})
        res_uuids = [res_lease.to_dict()["uuid"] for res_lease in res]

        self.assertEqual(3, res.count())
        self.assertIn(test_lease_1["uuid"], res_uuids)
        self.assertIn(test_lease_2["uuid"], res_uuids)
        self.assertIn(test_lease_3["uuid"], res_uuids)

    def test_lease_get_all_filter_by_time(self):
        api.lease_create(test_lease_1)
        api.lease_create(test_lease_2)
        api.lease_create(test_lease_3)

        start_time = test_lease_2["start_time"] + datetime.timedelta(days=1)
        end_time = test_lease_2["end_time"] + datetime.timedelta(days=-1)

        res = api.lease_get_all({"start_time": start_time, "end_time": end_time})
        res_uuids = [res_lease.to_dict()["uuid"] for res_lease in res]

        self.assertEqual(1, res.count())
        self.assertIn(test_lease_2["uuid"], res_uuids)

    def test_lease_get_all_filter_by_time_within(self):
        api.lease_create(test_lease_1)
        api.lease_create(test_lease_2)
        api.lease_create(test_lease_3)
        api.lease_create(test_lease_6)

        start_time = test_lease_1["end_time"] + datetime.timedelta(days=-1)
        end_time = test_lease_2["start_time"] + datetime.timedelta(days=1)

        res = api.lease_get_all(
            {
                "start_time": start_time,
                "end_time": end_time,
                "time_filter_type": "within",
            }
        )
        res_uuids = [res_lease.to_dict()["uuid"] for res_lease in res]

        self.assertEqual(3, res.count())
        self.assertIn(test_lease_1["uuid"], res_uuids)
        self.assertIn(test_lease_2["uuid"], res_uuids)
        self.assertIn(test_lease_6["uuid"], res_uuids)

    def test_lease_get_all_filter_by_project_or_owner_id(self):
        api.lease_create(test_lease_1)
        api.lease_create(test_lease_2)
        api.lease_create(test_lease_3)
        api.lease_create(test_lease_4)
        api.lease_create(test_lease_5)

        res = api.lease_get_all({"project_or_owner_id": "0wn3r"})
        res_uuids = [res_lease.to_dict()["uuid"] for res_lease in res]

        self.assertEqual(3, res.count())
        self.assertIn(test_lease_1["uuid"], res_uuids)
        self.assertIn(test_lease_2["uuid"], res_uuids)
        self.assertIn(test_lease_5["uuid"], res_uuids)

    def test_lease_create(self):
        o1 = api.offer_create(test_offer_2)
        test_lease_4["offer_uuid"] = o1.uuid
        l1 = api.lease_create(test_lease_4)
        l2 = api.lease_get_all({}).all()
        assert len(l2) == 1
        assert l2[0].to_dict() == l1.to_dict()

    def test_lease_update(self):
        o1 = api.offer_create(test_offer_2)
        test_lease_4["offer_uuid"] = o1.uuid
        l1 = api.lease_create(test_lease_4)
        values = {
            "start_time": test_lease_5["start_time"],
            "end_time": test_lease_5["end_time"],
        }
        api.lease_update(l1.uuid, values)
        l1 = api.lease_get_by_uuid(l1.uuid)
        self.assertEqual(test_lease_5["start_time"], l1.start_time)
        self.assertEqual(test_lease_5["end_time"], l1.end_time)

    def test_lease_update_invalid_time(self):
        o1 = api.offer_create(test_offer_3)
        test_lease_4["offer_uuid"] = o1.uuid
        l1 = api.lease_create(test_lease_4)
        values = {"start_time": now + datetime.timedelta(days=101), "end_time": now}
        self.assertRaises(e.InvalidTimeRange, api.lease_update, l1.uuid, values)

    def test_lease_destroy(self):
        o1 = api.offer_create(test_offer_2)
        test_lease_4["offer_uuid"] = o1.uuid
        l1 = api.lease_create(test_lease_4)
        api.lease_destroy(l1.uuid)
        self.assertEqual(api.lease_get_by_uuid("lease_4"), None)

    def test_lease_destroy_not_found(self):
        self.assertEqual(api.lease_get_by_uuid("lease_4"), None)


class TestLeaseVerifyChildAvailability(base.DBTestCase):
    def setUp(self):
        super(TestLeaseVerifyChildAvailability, self).setUp()

        self.parent_lease_data = dict(
            uuid=uuidutils.generate_uuid(),
            project_id=uuidutils.generate_uuid(),
            owner_id=uuidutils.generate_uuid(),
            resource_uuid="1111",
            resource_type="dummy_node",
            purpose="test_purpose",
            start_time=now + datetime.timedelta(days=50),
            end_time=now + datetime.timedelta(days=100),
            status=statuses.ACTIVE,
        )
        self.child_lease_data = dict(
            uuid=uuidutils.generate_uuid(),
            project_id=uuidutils.generate_uuid(),
            owner_id=uuidutils.generate_uuid(),
            parent_lease_uuid=self.parent_lease_data["uuid"],
            resource_uuid="1111",
            resource_type="dummy_node",
            purpose="test_purpose",
            start_time=now + datetime.timedelta(days=60),
            end_time=now + datetime.timedelta(days=70),
            status=statuses.ACTIVE,
        )
        self.child_offer_data = dict(
            uuid=uuidutils.generate_uuid(),
            project_id=uuidutils.generate_uuid(),
            parent_lease_uuid=self.parent_lease_data["uuid"],
            resource_uuid="1111",
            resource_type="dummy_node",
            start_time=now + datetime.timedelta(days=70),
            end_time=now + datetime.timedelta(days=80),
            status=statuses.AVAILABLE,
        )

    def test_lease_verify_child_availability(self):
        parent_lease = api.lease_create(self.parent_lease_data)

        start = self.parent_lease_data["start_time"] + datetime.timedelta(days=1)
        end = self.parent_lease_data["end_time"] + datetime.timedelta(days=-1)
        api.lease_verify_child_availability(parent_lease, start, end)

        start = self.parent_lease_data["start_time"] + datetime.timedelta(days=-1)
        end = self.parent_lease_data["end_time"] + datetime.timedelta(days=-1)
        self.assertRaises(
            e.LeaseNoTimeAvailabilities,
            api.lease_verify_child_availability,
            parent_lease,
            start,
            end,
        )

        start = self.parent_lease_data["start_time"] + datetime.timedelta(days=1)
        end = self.parent_lease_data["end_time"] + datetime.timedelta(days=1)
        self.assertRaises(
            e.LeaseNoTimeAvailabilities,
            api.lease_verify_child_availability,
            parent_lease,
            start,
            end,
        )

        start = self.parent_lease_data["start_time"] + datetime.timedelta(days=-1)
        end = self.parent_lease_data["end_time"] + datetime.timedelta(days=1)
        self.assertRaises(
            e.LeaseNoTimeAvailabilities,
            api.lease_verify_child_availability,
            parent_lease,
            start,
            end,
        )

    def test_lease_verify_child_availability_lease_conflict(self):
        parent_lease = api.lease_create(self.parent_lease_data)
        api.lease_create(self.child_lease_data)

        start = self.child_lease_data["start_time"] + datetime.timedelta(days=-5)
        end = self.child_lease_data["start_time"] + datetime.timedelta(days=-1)
        api.lease_verify_child_availability(parent_lease, start, end)

        start = self.child_lease_data["end_time"] + datetime.timedelta(days=1)
        end = self.child_lease_data["end_time"] + datetime.timedelta(days=5)
        api.lease_verify_child_availability(parent_lease, start, end)

        start = self.child_lease_data["start_time"] + datetime.timedelta(days=1)
        end = self.child_lease_data["end_time"] + datetime.timedelta(days=5)
        self.assertRaises(
            e.LeaseNoTimeAvailabilities,
            api.lease_verify_child_availability,
            parent_lease,
            start,
            end,
        )

        start = self.child_lease_data["start_time"] + datetime.timedelta(days=-1)
        end = self.child_lease_data["end_time"] + datetime.timedelta(days=-1)
        self.assertRaises(
            e.LeaseNoTimeAvailabilities,
            api.lease_verify_child_availability,
            parent_lease,
            start,
            end,
        )

    def test_lease_verify_child_availability_offer_conflict(self):
        parent_lease = api.lease_create(self.parent_lease_data)
        api.offer_create(self.child_offer_data)

        start = self.child_offer_data["start_time"] + datetime.timedelta(days=-5)
        end = self.child_offer_data["start_time"] + datetime.timedelta(days=-1)
        api.lease_verify_child_availability(parent_lease, start, end)

        start = self.child_offer_data["end_time"] + datetime.timedelta(days=1)
        end = self.child_offer_data["end_time"] + datetime.timedelta(days=5)
        api.lease_verify_child_availability(parent_lease, start, end)

        start = self.child_offer_data["start_time"] + datetime.timedelta(days=1)
        end = self.child_offer_data["end_time"] + datetime.timedelta(days=5)
        self.assertRaises(
            e.LeaseNoTimeAvailabilities,
            api.lease_verify_child_availability,
            parent_lease,
            start,
            end,
        )

        start = self.child_offer_data["start_time"] + datetime.timedelta(days=-1)
        end = self.child_offer_data["end_time"] + datetime.timedelta(days=-1)
        self.assertRaises(
            e.LeaseNoTimeAvailabilities,
            api.lease_verify_child_availability,
            parent_lease,
            start,
            end,
        )


class TestResourceVerifyAvailabilityAPI(base.DBTestCase):
    def test_resource_verify_availability_offer_conflict(self):
        o1 = api.offer_create(test_offer_4)
        r_type = o1.resource_type
        r_uuid = o1.resource_uuid

        start = test_offer_4["end_time"] + datetime.timedelta(days=1)
        end = test_offer_4["end_time"] + datetime.timedelta(days=5)
        api.resource_verify_availability(r_type, r_uuid, start, end)

        start = test_offer_4["start_time"] + datetime.timedelta(days=1)
        end = test_offer_4["end_time"] + datetime.timedelta(days=-1)
        self.assertRaises(
            e.ResourceTimeConflict,
            api.resource_verify_availability,
            r_type,
            r_uuid,
            start,
            end,
        )

        start = test_offer_4["start_time"] + datetime.timedelta(days=-1)
        end = test_offer_4["end_time"] + datetime.timedelta(days=1)
        self.assertRaises(
            e.ResourceTimeConflict,
            api.resource_verify_availability,
            r_type,
            r_uuid,
            start,
            end,
        )

        start = test_offer_4["start_time"] + datetime.timedelta(days=-1)
        end = test_offer_4["start_time"] + datetime.timedelta(days=1)
        self.assertRaises(
            e.ResourceTimeConflict,
            api.resource_verify_availability,
            r_type,
            r_uuid,
            start,
            end,
        )

        start = test_offer_4["end_time"] + datetime.timedelta(days=-1)
        end = test_offer_4["end_time"] + datetime.timedelta(days=1)
        self.assertRaises(
            e.ResourceTimeConflict,
            api.resource_verify_availability,
            r_type,
            r_uuid,
            start,
            end,
        )

    def test_resource_verify_availability_lease_conflict(self):
        test_lease = api.lease_create(test_lease_1)
        r_type = test_lease.resource_type
        r_uuid = test_lease.resource_uuid

        start = test_lease_1["end_time"] + datetime.timedelta(days=1)
        end = test_lease_1["end_time"] + datetime.timedelta(days=5)
        api.resource_verify_availability(r_type, r_uuid, start, end)

        start = test_lease_1["start_time"] + datetime.timedelta(days=1)
        end = test_lease_1["end_time"] + datetime.timedelta(days=-1)
        self.assertRaises(
            e.ResourceTimeConflict,
            api.resource_verify_availability,
            r_type,
            r_uuid,
            start,
            end,
        )

        start = test_lease_1["start_time"] + datetime.timedelta(days=-1)
        end = test_lease_1["end_time"] + datetime.timedelta(days=1)
        self.assertRaises(
            e.ResourceTimeConflict,
            api.resource_verify_availability,
            r_type,
            r_uuid,
            start,
            end,
        )

        start = test_lease_1["start_time"] + datetime.timedelta(days=-1)
        end = test_lease_1["start_time"] + datetime.timedelta(days=1)
        self.assertRaises(
            e.ResourceTimeConflict,
            api.resource_verify_availability,
            r_type,
            r_uuid,
            start,
            end,
        )

        start = test_lease_1["end_time"] + datetime.timedelta(days=-1)
        end = test_lease_1["end_time"] + datetime.timedelta(days=1)
        self.assertRaises(
            e.ResourceTimeConflict,
            api.resource_verify_availability,
            r_type,
            r_uuid,
            start,
            end,
        )


class TestEventAPI(base.DBTestCase):
    def test_event_get_all(self):
        api.event_create(test_event_1)
        api.event_create(test_event_2)

        events = api.event_get_all({})
        event_ids = [event.to_dict()["id"] for event in events]

        self.assertEqual(2, events.count())
        self.assertIn(test_event_1["id"], event_ids)
        self.assertIn(test_event_2["id"], event_ids)

    def test_event_get_all_filter_by_last_event_time(self):
        api.event_create(test_event_1)
        api.event_create(test_event_2)
        api.event_create(test_event_3)

        events = api.event_get_all({"last_event_time": test_event_1["event_time"]})
        event_ids = [event.to_dict()["id"] for event in events]

        self.assertEqual(1, events.count())
        self.assertIn(test_event_2["id"], event_ids)

    def test_event_get_all_filter_by_last_event_id(self):
        api.event_create(test_event_1)
        api.event_create(test_event_2)
        api.event_create(test_event_3)

        events = api.event_get_all({"last_event_id": 1})
        event_ids = [event.to_dict()["id"] for event in events]

        self.assertEqual(2, events.count())
        self.assertIn(test_event_2["id"], event_ids)
        self.assertIn(test_event_3["id"], event_ids)

    def test_event_get_all_filter_by_lessee_or_owner_id(self):
        api.event_create(test_event_1)
        api.event_create(test_event_2)
        api.event_create(test_event_3)

        events = api.event_get_all({"lessee_or_owner_id": "0wn3r"})
        event_ids = [event.to_dict()["id"] for event in events]

        self.assertEqual(2, events.count())
        self.assertIn(test_event_1["id"], event_ids)
        self.assertIn(test_event_2["id"], event_ids)

    def test_lease_create(self):
        event = api.event_create(test_event_1)
        events = api.event_get_all({}).all()
        assert len(events) == 1
        assert events[0].to_dict() == event.to_dict()


class TestConsoleAuthTokenAPI(base.DBTestCase):
    def test_console_auth_token_create_and_get(self):
        c = api.console_auth_token_create(test_cat_1)
        cat = api.console_auth_token_get_by_token_hash("test-hash-1")
        assert c.to_dict() == cat.to_dict()

    def test_console_auth_token_destroy_by_node_uuid(self):
        c1 = api.console_auth_token_create(test_cat_1)
        api.console_auth_token_create(test_cat_2)
        api.console_auth_token_destroy_by_node_uuid("test-node-2")
        cat1 = api.console_auth_token_get_by_token_hash("test-hash-1")
        cat2 = api.console_auth_token_get_by_token_hash("test-hash-2")
        assert c1.to_dict() == cat1.to_dict()
        assert cat2 is None

    def test_console_auth_token_destroy_expired(self):
        api.console_auth_token_create(test_cat_1)
        c2 = api.console_auth_token_create(test_cat_2)
        api.console_auth_token_destroy_expired()
        cat1 = api.console_auth_token_get_by_token_hash("test-hash-1")
        cat2 = api.console_auth_token_get_by_token_hash("test-hash-2")
        assert cat1 is None
        assert c2.to_dict() == cat2.to_dict()
