Upgrade service tests

This commit is contained in:
Marc 2014-10-01 21:03:16 +00:00
parent 276c02c2fd
commit 647bc43a5a
11 changed files with 94 additions and 61 deletions

View File

@ -1,4 +1,5 @@
from orchestra.apps.accounts.models import Account from orchestra.apps.accounts.models import Account
from orchestra.core import services
def get_related_objects(origin, max_depth=2): def get_related_objects(origin, max_depth=2):
@ -9,7 +10,6 @@ def get_related_objects(origin, max_depth=2):
flexibility. A more comprehensive approach may be considered if flexibility. A more comprehensive approach may be considered if
a use-case calls for it. a use-case calls for it.
""" """
def related_iterator(node): def related_iterator(node):
for field in node._meta.virtual_fields: for field in node._meta.virtual_fields:
if hasattr(field, 'ct_field'): if hasattr(field, 'ct_field'):
@ -26,7 +26,7 @@ def get_related_objects(origin, max_depth=2):
return None return None
node = models[-1] node = models[-1]
if len(models) > 1: if len(models) > 1:
if hasattr(node, 'account') or isinstance(node, Account): if type(node) in services:
return node return node
for related in related_iterator(node): for related in related_iterator(node):
if related and related not in models: if related and related not in models:

View File

@ -14,7 +14,7 @@ from django.contrib.contenttypes.models import ContentType
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from orchestra.core import accounts from orchestra.core import accounts, services
from orchestra.models import queryset from orchestra.models import queryset
from orchestra.utils.python import import_class from orchestra.utils.python import import_class
@ -71,6 +71,7 @@ class OrderQuerySet(models.QuerySet):
for order in orders: for order in orders:
bp = service.handler.get_billing_point(order, **options) bp = service.handler.get_billing_point(order, **options)
end = max(end, bp) end = max(end, bp)
# FIXME exclude cancelled except cancelled and billed > ini
qs = qs | Q( qs = qs | Q(
Q(service=service, account=account_id, registered_on__lt=end) & Q(service=service, account=account_id, registered_on__lt=end) &
Q(Q(billed_until__isnull=True) | Q(billed_until__lt=end)) Q(Q(billed_until__isnull=True) | Q(billed_until__lt=end))
@ -236,27 +237,26 @@ class MetricStorage(models.Model):
accounts.register(Order) accounts.register(Order)
_excluded_models = (MetricStorage, LogEntry, Order, ContentType, MigrationRecorder.Migration) # TODO build a cache hash table {model: related, model: None}
@receiver(post_delete, dispatch_uid="orders.cancel_orders") @receiver(post_delete, dispatch_uid="orders.cancel_orders")
def cancel_orders(sender, **kwargs): def cancel_orders(sender, **kwargs):
if sender not in _excluded_models: if sender._meta.app_label not in settings.ORDERS_EXCLUDED_APPS:
instance = kwargs['instance'] instance = kwargs['instance']
if hasattr(instance, 'account'): if type(instance) in services:
for order in Order.objects.by_object(instance).active(): for order in Order.objects.by_object(instance).active():
order.cancel() order.cancel()
else: elif not hasattr(instance, 'account'):
related = helpers.get_related_objects(instance) related = helpers.get_related_objects(instance)
if related and related != instance: if related and related != instance:
Order.update_orders(related) Order.update_orders(related)
@receiver(post_save, dispatch_uid="orders.update_orders") @receiver(post_save, dispatch_uid="orders.update_orders")
def update_orders(sender, **kwargs): def update_orders(sender, **kwargs):
if sender not in _excluded_models: if sender._meta.app_label not in settings.ORDERS_EXCLUDED_APPS:
instance = kwargs['instance'] instance = kwargs['instance']
if hasattr(instance, 'account'): if type(instance) in services:
Order.update_orders(instance) Order.update_orders(instance)
else: elif not hasattr(instance, 'account'):
related = helpers.get_related_objects(instance) related = helpers.get_related_objects(instance)
if related and related != instance: if related and related != instance:
Order.update_orders(related) Order.update_orders(related)

View File

@ -6,3 +6,16 @@ ORDERS_BILLING_BACKEND = getattr(settings, 'ORDERS_BILLING_BACKEND',
ORDERS_SERVICE_MODEL = getattr(settings, 'ORDERS_SERVICE_MODEL', 'services.Service') ORDERS_SERVICE_MODEL = getattr(settings, 'ORDERS_SERVICE_MODEL', 'services.Service')
ORDERS_EXCLUDED_APPS = getattr(settings, 'ORDERS_EXCLUDED_APPS', (
'orders',
'admin',
'contenttypes',
'auth',
'migrations',
'sessions',
'orchestration',
'bills',
# Do not put services here (plans)
))

View File

@ -177,8 +177,7 @@ def create_resource_relation():
data = self.obj.resource_set.get(resource__name=attr) data = self.obj.resource_set.get(resource__name=attr)
except ResourceData.DoesNotExist: except ResourceData.DoesNotExist:
model = self.obj._meta.model_name model = self.obj._meta.model_name
resource = Resource.objects.get(content_type__model=model, resource = Resource.objects.get(content_type__model=model, name=attr, is_active=True)
name=attr, is_active=True)
data = ResourceData(content_object=self.obj, resource=resource) data = ResourceData(content_object=self.obj, resource=resource)
return data return data

View File

@ -1,16 +1,9 @@
from orchestra.apps.accounts.models import Account from orchestra.apps.accounts.models import Account
from orchestra.apps.users.models import User
from orchestra.utils.tests import BaseTestCase, random_ascii from orchestra.utils.tests import BaseTestCase, random_ascii
# TODO remove this shit
class BaseBillingTest(BaseTestCase): class BaseBillingTest(BaseTestCase):
def create_account(self): pass
account = Account.objects.create()
username = 'account_%s' % random_ascii(5)
user = User.objects.create_user(username=username, account=account)
account.user = user
account.save()
return account
# TODO web disk # TODO web disk

View File

@ -5,7 +5,7 @@ from dateutil.relativedelta import relativedelta
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.utils import timezone from django.utils import timezone
from orchestra.apps.users.models import User from orchestra.apps.systemusers.models import SystemUser
from orchestra.utils.tests import random_ascii from orchestra.utils.tests import random_ascii
from ... import settings from ... import settings
@ -18,8 +18,8 @@ class FTPBillingTest(BaseBillingTest):
def create_ftp_service(self): def create_ftp_service(self):
return Service.objects.create( return Service.objects.create(
description="FTP Account", description="FTP Account",
content_type=ContentType.objects.get_for_model(User), content_type=ContentType.objects.get_for_model(SystemUser),
match='not user.is_main and user.has_posix()', match='not systemuser.is_main',
billing_period=Service.ANUAL, billing_period=Service.ANUAL,
billing_point=Service.FIXED_DATE, billing_point=Service.FIXED_DATE,
is_fee=False, is_fee=False,
@ -36,10 +36,7 @@ class FTPBillingTest(BaseBillingTest):
if not account: if not account:
account = self.create_account() account = self.create_account()
username = '%s_ftp' % random_ascii(10) username = '%s_ftp' % random_ascii(10)
user = User.objects.create_user(username=username, account=account) return SystemUser.objects.create_user(username, account=account)
POSIX = user._meta.get_field_by_name('posix')[0].model
POSIX.objects.create(user=user)
return user
def test_ftp_account_1_year_fiexed(self): def test_ftp_account_1_year_fiexed(self):
service = self.create_ftp_service() service = self.create_ftp_service()

View File

@ -13,7 +13,7 @@ from . import BaseBillingTest
class BaseTrafficBillingTest(BaseBillingTest): class BaseTrafficBillingTest(BaseBillingTest):
METRIC = 'account.resources.traffic.used' TRAFFIC_METRIC = 'account.resources.traffic.used'
def create_traffic_service(self): def create_traffic_service(self):
service = Service.objects.create( service = Service.objects.create(
@ -23,7 +23,7 @@ class BaseTrafficBillingTest(BaseBillingTest):
billing_period=Service.MONTHLY, billing_period=Service.MONTHLY,
billing_point=Service.FIXED_DATE, billing_point=Service.FIXED_DATE,
is_fee=False, is_fee=False,
metric=self.METRIC, metric=self.TRAFFIC_METRIC,
pricing_period=Service.BILLING_PERIOD, pricing_period=Service.BILLING_PERIOD,
rate_algorithm=Service.STEP_PRICE, rate_algorithm=Service.STEP_PRICE,
on_cancel=Service.NOTHING, on_cancel=Service.NOTHING,
@ -50,7 +50,7 @@ class BaseTrafficBillingTest(BaseBillingTest):
return self.resource return self.resource
def report_traffic(self, account, value): def report_traffic(self, account, value):
MonitorData.objects.create(monitor='FTPTraffic', content_object=account.user, value=value) MonitorData.objects.create(monitor='FTPTraffic', content_object=account.systemusers.get(), value=value)
data = ResourceData.get_or_create(account, self.resource) data = ResourceData.get_or_create(account, self.resource)
data.update() data.update()
@ -90,7 +90,7 @@ class TrafficBillingTest(BaseTrafficBillingTest):
class TrafficPrepayBillingTest(BaseTrafficBillingTest): class TrafficPrepayBillingTest(BaseTrafficBillingTest):
METRIC = ("max(" TRAFFIC_METRIC = ("max("
"(account.resources.traffic.used or 0) - " "(account.resources.traffic.used or 0) - "
"getattr(account.miscellaneous.filter(is_active=True, service__name='traffic prepay').last(), 'amount', 0)" "getattr(account.miscellaneous.filter(is_active=True, service__name='traffic prepay').last(), 'amount', 0)"
", 0)" ", 0)"
@ -126,8 +126,8 @@ class TrafficPrepayBillingTest(BaseTrafficBillingTest):
def test_traffic_prepay(self): def test_traffic_prepay(self):
self.create_traffic_service() self.create_traffic_service()
self.create_prepay_service() self.create_prepay_service()
account = self.create_account()
self.create_traffic_resource() self.create_traffic_resource()
account = self.create_account()
now = timezone.now() now = timezone.now()
self.create_prepay(10, account=account) self.create_prepay(10, account=account)

View File

@ -5,8 +5,8 @@ from django.contrib.contenttypes.models import ContentType
from django.utils import timezone from django.utils import timezone
from orchestra.apps.accounts.models import Account from orchestra.apps.accounts.models import Account
from orchestra.apps.users.models import User from orchestra.apps.systemusers.models import SystemUser
from orchestra.utils.tests import BaseTestCase from orchestra.utils.tests import BaseTestCase, random_ascii
from .. import helpers from .. import helpers
from ..models import Service, Plan from ..models import Service, Plan
@ -28,22 +28,14 @@ class Order(object):
class HandlerTests(BaseTestCase): class HandlerTests(BaseTestCase):
DEPENDENCIES = ( DEPENDENCIES = (
'orchestra.apps.orders', 'orchestra.apps.orders',
'orchestra.apps.users', 'orchestra.apps.systemusers',
'orchestra.apps.users.roles.posix',
) )
def create_account(self):
account = Account.objects.create()
user = User.objects.create_user(username='rata_palida', account=account)
account.user = user
account.save()
return account
def create_ftp_service(self): def create_ftp_service(self):
service = Service.objects.create( service = Service.objects.create(
description="FTP Account", description="FTP Account",
content_type=ContentType.objects.get_for_model(User), content_type=ContentType.objects.get_for_model(SystemUser),
match='not user.is_main and user.has_posix()', match='not systemuser.is_main',
billing_period=Service.ANUAL, billing_period=Service.ANUAL,
billing_point=Service.FIXED_DATE, billing_point=Service.FIXED_DATE,
is_fee=False, is_fee=False,

View File

@ -15,6 +15,7 @@ class SystemUserQuerySet(models.QuerySet):
user = super(SystemUserQuerySet, self).create(username=username, **kwargs) user = super(SystemUserQuerySet, self).create(username=username, **kwargs)
user.set_password(password) user.set_password(password)
user.save(update_fields=['password']) user.save(update_fields=['password'])
return user
class SystemUser(models.Model): class SystemUser(models.Model):

View File

@ -2,6 +2,7 @@ from functools import partial
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from selenium.webdriver.support.select import Select
from orchestra.apps.accounts.models import Account from orchestra.apps.accounts.models import Account
from orchestra.apps.orchestration.models import Server, Route from orchestra.apps.orchestration.models import Server, Route
@ -9,6 +10,7 @@ from orchestra.utils.system import run
from orchestra.utils.tests import BaseLiveServerTestCase, random_ascii from orchestra.utils.tests import BaseLiveServerTestCase, random_ascii
from ... import backends from ... import backends
from ...models import SystemUser
r = partial(run, silent=True, display=False) r = partial(run, silent=True, display=False)
@ -40,6 +42,9 @@ class SystemUserMixin(object):
def update(self): def update(self):
raise NotImplementedError raise NotImplementedError
def disable(self):
raise NotImplementedError
def test_create_systemuser(self): def test_create_systemuser(self):
username = '%s_systemuser' % random_ascii(10) username = '%s_systemuser' % random_ascii(10)
password = '@!?%spppP001' % random_ascii(5) password = '@!?%spppP001' % random_ascii(5)
@ -56,6 +61,15 @@ class SystemUserMixin(object):
self.delete(username) self.delete(username)
self.assertEqual(1, r("id %s" % username, error_codes=[0,1]).return_code) self.assertEqual(1, r("id %s" % username, error_codes=[0,1]).return_code)
def test_update_systemuser(self):
pass
# TODO
def test_disable_systemuser(self):
pass
# TODO
# TODO test with ftp and ssh clients?
class RESTSystemUserMixin(SystemUserMixin): class RESTSystemUserMixin(SystemUserMixin):
def setUp(self): def setUp(self):
@ -73,16 +87,38 @@ class RESTSystemUserMixin(SystemUserMixin):
pass pass
# TODO
class AdminSystemUserMixin(SystemUserMixin): class AdminSystemUserMixin(SystemUserMixin):
def setUp(self): def setUp(self):
super(AdminSystemUserMixin, self).setUp() super(AdminSystemUserMixin, self).setUp()
self.admin_login() self.admin_login()
def add(self, username, password): def add(self, username, password):
pass url = self.live_server_url + reverse('admin:systemusers_systemuser_add')
self.selenium.get(url)
username_field = self.selenium.find_element_by_id('id_username')
username_field.send_keys(username)
password_field = self.selenium.find_element_by_id('id_password1')
password_field.send_keys(password)
password_field = self.selenium.find_element_by_id('id_password2')
password_field.send_keys(password)
account_input = self.selenium.find_element_by_id('id_account')
account_select = Select(account_input)
account_select.select_by_value(str(self.account.pk))
username_field.submit()
self.assertNotEqual(url, self.selenium.current_url)
def delete(self, username): def delete(self, username):
user = SystemUser.objects.get(username=username)
url = self.live_server_url + reverse('admin:systemusers_systemuser_delete', args=(user.pk,))
self.selenium.get(url)
confirmation = self.selenium.find_element_by_name('post')
confirmation.submit()
def disable(self, username):
pass pass
def update(self): def update(self):

View File

@ -12,6 +12,10 @@ from xvfbwrapper import Xvfb
from orchestra.apps.accounts.models import Account from orchestra.apps.accounts.models import Account
def random_ascii(length):
return ''.join([random.choice(string.hexdigits) for i in range(0, length)]).lower()
class AppDependencyMixin(object): class AppDependencyMixin(object):
DEPENDENCIES = () DEPENDENCIES = ()
@ -49,13 +53,15 @@ class AppDependencyMixin(object):
class BaseTestCase(TestCase, AppDependencyMixin): class BaseTestCase(TestCase, AppDependencyMixin):
pass def create_account(self, superuser=False):
username = '%s_superaccount' % random_ascii(5)
password = 'orchestra'
if superuser:
return Account.objects.create_superuser(username, password=password, email='orchestra@orchestra.org')
return Account.objects.create_user(username, password=password, email='orchestra@orchestra.org')
class BaseLiveServerTestCase(AppDependencyMixin, LiveServerTestCase): class BaseLiveServerTestCase(AppDependencyMixin, LiveServerTestCase):
ACCOUNT_USERNAME = 'orchestra'
ACCOUNT_PASSWORD = 'orchestra'
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
cls.vdisplay = Xvfb() cls.vdisplay = Xvfb()
@ -70,11 +76,11 @@ class BaseLiveServerTestCase(AppDependencyMixin, LiveServerTestCase):
super(BaseLiveServerTestCase, cls).tearDownClass() super(BaseLiveServerTestCase, cls).tearDownClass()
def create_account(self, superuser=False): def create_account(self, superuser=False):
username = '%s_superaccount' % random_ascii(5)
password = 'orchestra'
if superuser: if superuser:
return Account.objects.create_superuser(self.ACCOUNT_USERNAME, return Account.objects.create_superuser(username, password=password, email='orchestra@orchestra.org')
password=self.ACCOUNT_PASSWORD, email='orchestra@orchestra.org') return Account.objects.create_user(username, password=password, email='orchestra@orchestra.org')
return Account.objects.create_user(self.ACCOUNT_USERNAME,
password=self.ACCOUNT_PASSWORD, email='orchestra@orchestra.org')
def setUp(self): def setUp(self):
super(BaseLiveServerTestCase, self).setUp() super(BaseLiveServerTestCase, self).setUp()
@ -96,7 +102,3 @@ class BaseLiveServerTestCase(AppDependencyMixin, LiveServerTestCase):
def rest_login(self): def rest_login(self):
self.rest.login(username=self.ACCOUNT_USERNAME, password=self.ACCOUNT_PASSWORD) self.rest.login(username=self.ACCOUNT_USERNAME, password=self.ACCOUNT_PASSWORD)
def random_ascii(length):
return ''.join([random.choice(string.hexdigits) for i in range(0, length)]).lower()