distil/tests/test_interface.py

396 lines
12 KiB
Python

import unittest
from artifice import interface
from artifice.interface import Artifice
import mock
import random
import json
from artifice.models.db_models import Tenant as tenant_model
from artifice.models.db_models import UsageEntry, Resource
# import copy
from sqlalchemy import create_engine
from artifice.models import Session
from datetime import datetime, timedelta
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
"""
This module tests interacting with the Ceilometer web service.
This will require an active Ceilometer with data in it, or,
"""
# @mock.patch("artifice.models.Session")
# @mock.patch("keystoneclient.v2_0.client.Client")
# @mock.patch("sqlalchemy.create_engine")
# def test_instance_artifice(self, sqlmock, keystone, session):
# """Tests that artifice correctly instances."""
# from artifice.interface import Artifice
# # from artifice.models import usage
config = {
"main": {
"host_mapper": None
},
"database": {
"username": "aurynn",
"password": "aurynn",
"host": "localhost",
"port": "5433",
"database": "artifice"
},
"openstack": {
"username": "foo",
"password": "bar",
"default_tenant": "asdf",
"authentication_url": "http://foo"
},
"ceilometer": {
"host": 'http://whee'
},
"invoices": {
"plugin": "json"
}
}
# Enter in a whoooooole bunch of mock data.
TENANTS = [
{u'enabled': True,
u'description': None,
u'name': u'demo',
u'id': u'931dc699f9934021bb4a2b1088ba4d3b'}
]
DATACENTRE = "testcenter"
import os
try:
fn = os.path.abspath(__file__)
path, f = os.path.split(fn)
except NameError:
path = os.getcwd()
fh = open(os.path.join(path, "data/resources.json"))
resources = json.loads(fh.read())
fh.close()
i = 0
mappings = {}
hosts = set([resource["metadata"]["host"] for resource
in resources if resource["metadata"].get("host")])
while True:
try:
fh = open(os.path.join(path, "data/map_fixture_%s.json" % i))
d = json.loads(fh.read())
fh.close()
mappings.update(d)
i += 1
except IOError:
break
# Mappings should now be a set of resources.
AUTH_TOKEN = "ASDFTOKEN"
storages = []
vms = []
networks = []
# res = {"vms": [], "net": [], 'storage': [], "ports":[], "ips": []}
# res = {"vms": [], "network": [], 'storage': [], "ports":[]}
res = {"vms": [], "volumes": [], 'objects': [], "networks": [], "ips": []}
class InternalResource(object):
def __init__(self, resource):
self.resource = resource
# def __getitem__(self, item):
# return self.resource[item]
def __getattr__(self, attr):
return self.resource[attr]
def __str__(self):
return str(self.resource)
@property
def links(self):
return [MiniMeter(i) for i in self.resource['links']]
class MiniMeter(object):
def __init__(self, meter):
self._ = meter
@property
def link(self):
return self._["href"]
@property
def rel(self):
return self._["rel"]
def __getitem__(self, item):
return self._[item]
resources = [InternalResource(r) for r in resources]
for resource in resources:
rels = [link.rel for link in resource.links if link.rel != 'self']
if "image" in rels:
continue
elif "storage.objects.size" in rels:
# Unknown how this data layout happens yet.
# resource["_type"] = "storage"
res["objects"].append(resource)
elif "volume" in rels:
res["volumes"].append(resource)
elif "network.outgoing.bytes" in rels:
res["networks"].append(resource)
elif "state" in rels:
res["vms"].append(resource)
elif "ip.floating" in rels:
res["ips"].append(resource)
def resources_replacement(tester):
#
def repl(self, start, end):
tester.called_replacement_resources = True
return resources
class TestInterface(unittest.TestCase):
def setUp(self):
engine = create_engine(os.environ["DATABASE_URL"])
Session.configure(bind=engine)
Base.metadata.create_all(engine)
self.session = Session()
self.objects = []
self.session.rollback()
self.called_replacement_resources = False
self.resources = (res["networks"] + res["vms"] + res["objects"] +
res["volumes"] + res["ips"])
self.start = datetime.now() - timedelta(days=30)
self.end = datetime.now()
def tearDown(self):
self.session.query(UsageEntry).delete()
self.session.query(tenant_model).delete()
self.session.query(Resource).delete()
self.session.commit()
self.contents = None
self.resources = []
self.artifice = None
self.usage = None
@mock.patch("artifice.models.Session")
# @mock.patch("artifice.interface.get_meter")
# I don't think this will work
@mock.patch("artifice.interface.keystone")
@mock.patch("sqlalchemy.create_engine")
def test_get_usage(self, sqlmock, keystone, session):
# At this point, we prime the ceilometer/requests response
# system, so that what we return to usage is what we expect
# to get in the usage system.
keystone.auth_token = AUTH_TOKEN
# keystone.
self.assertTrue(TENANTS is not None)
def get_meter(self, start, end, auth):
# Returns meter data from our data up above
global mappings
data = mappings[self.link]
return data
interface.get_meter = get_meter
artifice = Artifice(config)
self.artifice = artifice
# Needed because this
artifice.auth.tenants.list.return_value = TENANTS
# this_config = copy.deepcopy(config["openstack"])
# this_config["tenant_name"] = this_config["default_tenant"]
# del this_config["default_tenant"]
keystone.assert_called_with(
username=config["openstack"]["username"],
password=config["openstack"]["password"],
tenant_name=config["openstack"]["default_tenant"],
auth_url=config["openstack"]["authentication_url"]
)
tenants = None
# try:
tenants = artifice.tenants
# except Exception as e:
# self.fail(e)
# self.assertEqual ( len(tenants.vms), 1 )
self.assertEqual(len(tenants), 1)
k = tenants.keys()[0]
t = tenants[k] # First tenant
self.assertTrue(isinstance(t, interface.Tenant))
# t.resources = resources_replacement(self)
# t.resources = mock.Mock(spec=interface.Resource)
t.resources = mock.create_autospec(interface.Resource, spec_set=True)
t.resources.return_value = self.resources
try:
hdc = getattr(artifice, "host_to_dc")
self.assertTrue(callable(hdc))
except AttributeError:
self.fail("Artifice object lacks host_to_dc method ")
# Replace the host_to_dc method with a mock that does what we need
# it to do, for the purposes of testing.
artifice.host_to_dc = mock.Mock()
artifice.host_to_dc.return_value = DATACENTRE
usage = t.usage(self.start, self.end)
# try:
# except Exception as e:
# self.fail(e)
# self.assertTrue( self.called_replacement_resources )
t.resources.assert_called_with(self.start, self.end)
# So, we should be able to assert a couple of things here
# What got called, when, and how.
for call in artifice.host_to_dc.call_args_list:
self.assertTrue(len(call[0]) == 1)
self.assertTrue(call[0][0] in hosts)
self.assertTrue(isinstance(usage, interface.Usage))
# self.assertEqual( len(usage.vms), 1 )
# self.assertEqual( len(usage.objects), 0)
# self.assertEqual( len(usage.volumes), 0)
# This is a fully qualified Usage object.
self.usage = usage
def add_element(self, from_):
self.resources.append(res[from_][random.randrange(len(res[from_]))])
self.test_get_usage()
usage = self.usage
# key = contents.keys()[0] # Key is the datacenter
self.assertTrue(isinstance(usage, interface.Usage))
try:
getattr(usage, from_)
# self.assertTrue( hasattr(usage, from_) )
except AttributeError:
self.fail("No property %s" % from_)
try:
getattr(usage, "vms")
except AttributeError:
self.fail("No property vms")
lens = {"vms": 5}
if from_ == "vms":
lens["vms"] = 6
else:
lens[from_] = 2
self.assertEqual(len(usage.vms), lens["vms"])
self.assertEqual(len(getattr(usage, from_)), lens[from_])
self.assertEqual(usage.vms[0].location, DATACENTRE)
def test_add_instance(self):
"""
Adds a new instance, tests that the returned data has both
Tests that if we create a new instance in the data,
we should get another instance in the returned contents.
"""
self.add_element("vms")
self.usage._vms = []
self.assertTrue(len(self.usage.vms) == 6)
def test_add_storage(self):
self.add_element("objects")
def test_correct_usage_values(self):
"""Usage data matches expected results:
tests that we get the usage data we expect from the processing
system as developed.
"""
self.test_get_usage()
usage = self.usage
for vm in usage.vms:
if vm.resource_id == "db8037b2-9f1c-4dd2-94dd-ea72f49a21d7":
self.assertEqual(vm.uptime, 1)
if vm.resource_id == "9a9e7c74-2a2f-4a30-bc75-fadcbc5f304a":
self.assertEqual(vm.uptime, 1)
if vm.resource_id == "0a57e3da-9e85-4690-8ba9-ee7573619ec3":
self.assertEqual(vm.uptime, 1)
if vm.resource_id == "de35c688-5a82-4ce5-a7e0-36245d2448bc":
self.assertEqual(vm.uptime, 1)
if vm.resource_id == "e404920f-cfc8-40ba-bc53-a5c610714bd9":
self.assertEqual(vm.uptime, 0)
for obj in usage.objects:
if obj.resource_id == "3f7b702e4ca14cd99aebf4c4320e00ec":
self.assertEqual(obj.size,
276.18937199999999165811459533870220184326171875)
for vol in usage.volumes:
if vol.resource_id == "e788c617-01e9-405b-823f-803f44fb3483":
self.assertEqual(vol.size, 0.000044999999999999996057840900842705877948901616036891937255859375)
if vol.resource_id == "6af83f4f-1f4f-40cf-810e-e3262dec718f":
self.assertEqual(vol.size, 0.000003000000000000000076002572291233860823922441340982913970947265625)
for net in usage.networks:
if (net.resource_id ==
"nova-instance-instance-00000002-fa163ee2d5f6"):
self.assertEqual(net.outgoing, 0.011821999999999999175770426518283784389495849609375)
self.assertEqual(net.incoming, 0.009733999999999999597211086665993207134306430816650390625)
if (net.resource_id ==
"nova-instance-instance-00000001-fa163edf2e3c"):
self.assertEqual(net.outgoing, 0.006305999999999999973410158560227500856854021549224853515625)
self.assertEqual(net.incoming, 0.00583999999999999970523578696202093851752579212188720703125)
if (net.resource_id ==
"nova-instance-instance-00000005-fa163ee2fde1"):
self.assertEqual(net.outgoing, 0.0134060000000000012487788580983760766685009002685546875)
self.assertEqual(net.incoming, 0.01079500000000000077549078270067184348590672016143798828125)
for ip in usage.ips:
if ip.resource_id == "84326068-5ccd-4a32-bcd2-c6c3af84d862":
self.assertEqual(ip.duration, 1)
if ip.resource_id == "2155db5c-4c7b-4787-90ff-7b8ded741c75":
self.assertEqual(ip.duration, 1)