Use freezegun for test time mockup

This commit is contained in:
Marc 2014-09-24 20:09:41 +00:00
parent c0e8e9f85d
commit 0de534f4e2
13 changed files with 183 additions and 90 deletions

View file

@ -109,3 +109,4 @@ at + clock time, midnight, noon- At 3:30 p.m., At 4:01, At noon
* latest by 'id' *always*
* replace add_now by default=lambda: timezone.now()

View file

@ -35,17 +35,21 @@ class Bill(models.Model):
(PENDING, _("Pending")),
(BAD_DEBT, _("Bad debt")),
)
BILL = 'BILL'
INVOICE = 'INVOICE'
AMENDMENTINVOICE = 'AMENDMENTINVOICE'
FEE = 'FEE'
AMENDMENTFEE = 'AMENDMENTFEE'
PROFORMA = 'PROFORMA'
TYPES = (
('INVOICE', _("Invoice")),
('AMENDMENTINVOICE', _("Amendment invoice")),
('FEE', _("Fee")),
('AMENDMENTFEE', _("Amendment Fee")),
('PROFORMA', _("Pro forma")),
(INVOICE, _("Invoice")),
(AMENDMENTINVOICE, _("Amendment invoice")),
(FEE, _("Fee")),
(AMENDMENTFEE, _("Amendment Fee")),
(PROFORMA, _("Pro forma")),
)
number = models.CharField(_("number"), max_length=16, unique=True,
blank=True)
number = models.CharField(_("number"), max_length=16, unique=True, blank=True)
account = models.ForeignKey('accounts.Account', verbose_name=_("account"),
related_name='%(class)s')
type = models.CharField(_("type"), max_length=16, choices=TYPES)
@ -63,7 +67,7 @@ class Bill(models.Model):
objects = BillManager()
class Meta:
get_latest_by = 'created_on'
get_latest_by = 'id'
def __unicode__(self):
return self.number
@ -101,8 +105,8 @@ class Bill(models.Model):
def set_number(self):
cls = type(self)
bill_type = self.get_type()
if bill_type == 'BILL':
raise TypeError("get_new_number() can not be used on a Bill class")
if bill_type == self.BILL:
raise TypeError('This method can not be used on BILL instances')
prefix = getattr(settings, 'BILLS_%s_NUMBER_PREFIX' % bill_type)
if self.is_open:
prefix = 'O{}'.format(prefix)
@ -117,8 +121,7 @@ class Bill(models.Model):
number_length = settings.BILLS_NUMBER_LENGTH
zeros = (number_length - len(str(number))) * '0'
number = zeros + str(number)
self.number = '{prefix}{year}{number}'.format(
prefix=prefix, year=year, number=number)
self.number = '{prefix}{year}{number}'.format(prefix=prefix, year=year, number=number)
def get_due_date(self, payment=None):
now = timezone.now()
@ -134,7 +137,7 @@ class Bill(models.Model):
self.due_on = self.get_due_date(payment=payment)
self.total = self.get_total()
self.html = self.render(payment=payment)
if self.get_type() != 'PROFORMA':
if self.get_type() != self.PROFORMA:
self.transactions.create(bill=self, source=payment, amount=self.total)
self.closed_on = timezone.now()
self.is_open = False
@ -175,8 +178,8 @@ class Bill(models.Model):
'default_due_date': self.get_due_date(payment=payment),
'now': timezone.now(),
})
template = getattr(settings, 'BILLS_%s_TEMPLATE' % self.get_type(),
settings.BILLS_DEFAULT_TEMPLATE)
template_name = 'BILLS_%s_TEMPLATE' % self.get_type()
template = getattr(settings, template_name, settings.BILLS_DEFAULT_TEMPLATE)
bill_template = loader.get_template(template)
html = bill_template.render(context)
html = html.replace('-pageskip-', '<pdf:nextpage />')
@ -234,8 +237,7 @@ class BillLine(models.Model):
""" Base model for bill item representation """
bill = models.ForeignKey(Bill, verbose_name=_("bill"), related_name='lines')
description = models.CharField(_("description"), max_length=256)
rate = models.DecimalField(_("rate"), blank=True, null=True,
max_digits=12, decimal_places=2)
rate = models.DecimalField(_("rate"), blank=True, null=True, max_digits=12, decimal_places=2)
quantity = models.DecimalField(_("quantity"), max_digits=12, decimal_places=2)
subtotal = models.DecimalField(_("subtotal"), max_digits=12, decimal_places=2)
tax = models.PositiveIntegerField(_("tax"))
@ -261,7 +263,7 @@ class BillLine(models.Model):
return total
def save(self, *args, **kwargs):
# TODO cost of this shit
# TODO cost and consistency of this shit
super(BillLine, self).save(*args, **kwargs)
if self.bill.is_open:
self.bill.total = self.bill.get_total()
@ -270,8 +272,7 @@ class BillLine(models.Model):
class BillSubline(models.Model):
""" Subline used for describing an item discount """
line = models.ForeignKey(BillLine, verbose_name=_("bill line"),
related_name='sublines')
line = models.ForeignKey(BillLine, verbose_name=_("bill line"), related_name='sublines')
description = models.CharField(_("description"), max_length=256)
total = models.DecimalField(max_digits=12, decimal_places=2)
# TODO type ? Volume and Compensation

View file

@ -57,7 +57,9 @@ class DomainAdmin(ChangeListDefaultFilter, AccountAdminMixin, ExtendedModelAdmin
list_filter = [TopDomainListFilter]
change_readonly_fields = ('name',)
search_fields = ['name', 'account__user__username']
default_changelist_filters = (('top_domain', 'True'),)
default_changelist_filters = (
('top_domain', 'True'),
)
form = DomainAdminForm
def structured_name(self, domain):

View file

@ -74,7 +74,9 @@ class Bind9MasterDomainBackend(ServiceController):
class Bind9SlaveDomainBackend(Bind9MasterDomainBackend):
verbose_name = _("Bind9 slave domain")
related_models = (('domains.Domain', 'origin'),)
related_models = (
('domains.Domain', 'origin'),
)
def save(self, domain):
context = self.get_context(domain)

View file

@ -161,7 +161,7 @@ class Message(models.Model):
created_on = models.DateTimeField(_("created on"), auto_now_add=True)
class Meta:
get_latest_by = "created_on"
get_latest_by = 'id'
def __unicode__(self):
return u"#%i" % self.id
@ -188,4 +188,6 @@ class TicketTracker(models.Model):
related_name='ticket_trackers')
class Meta:
unique_together = (('ticket', 'user'),)
unique_together = (
('ticket', 'user'),
)

View file

@ -66,7 +66,7 @@ class BackendLog(models.Model):
last_update = models.DateTimeField(_("last update"), auto_now=True)
class Meta:
get_latest_by = 'created'
get_latest_by = 'id'
@property
def execution_time(self):

View file

@ -81,9 +81,9 @@ class Order(models.Model):
related_name='orders')
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField(null=True)
service = models.ForeignKey(settings.ORDERS_SERVICE_MODEL,
verbose_name=_("service"), related_name='orders')
registered_on = models.DateField(_("registered"), auto_now_add=True) # TODO datetime field?
service = models.ForeignKey(settings.ORDERS_SERVICE_MODEL, verbose_name=_("service"),
related_name='orders')
registered_on = models.DateField(_("registered"), default=lambda: timezone.now())
cancelled_on = models.DateField(_("cancelled"), null=True, blank=True)
billed_on = models.DateField(_("billed on"), null=True, blank=True)
billed_until = models.DateField(_("billed until"), null=True, blank=True)
@ -93,6 +93,9 @@ class Order(models.Model):
content_object = generic.GenericForeignKey()
objects = OrderQuerySet.as_manager()
class Meta:
get_latest_by = 'id'
def __unicode__(self):
return str(self.service)
@ -180,6 +183,7 @@ class MetricStorage(models.Model):
order = models.ForeignKey(Order, verbose_name=_("order"), related_name='metrics')
value = models.DecimalField(_("value"), max_digits=16, decimal_places=2)
created_on = models.DateField(_("created"), auto_now_add=True)
# default=lambda: timezone.now())
updated_on = models.DateTimeField(_("updated"))
class Meta:
@ -203,9 +207,11 @@ class MetricStorage(models.Model):
metric.save()
_excluded_models = (MetricStorage, LogEntry, Order, ContentType, MigrationRecorder.Migration)
accounts.register(Order)
_excluded_models = (MetricStorage, LogEntry, Order, ContentType, MigrationRecorder.Migration)
@receiver(post_delete, dispatch_uid="orders.cancel_orders")
def cancel_orders(sender, **kwargs):
if sender not in _excluded_models:
@ -218,7 +224,6 @@ def cancel_orders(sender, **kwargs):
if related and related != instance:
Order.update_orders(related)
@receiver(post_save, dispatch_uid="orders.update_orders")
def update_orders(sender, **kwargs):
if sender not in _excluded_models:
@ -229,7 +234,3 @@ def update_orders(sender, **kwargs):
related = helpers.get_related_objects(instance)
if related and related != instance:
Order.update_orders(related)
accounts.register(Order)

View file

@ -2,10 +2,11 @@ import datetime
import decimal
import sys
from dateutil import relativedelta
from dateutil.relativedelta import relativedelta
from django.contrib.contenttypes.models import ContentType
from django.db.models import F
from django.utils import timezone
from freezegun import freeze_time
from orchestra.apps.accounts.models import Account
from orchestra.apps.mails.models import Mailbox
@ -56,21 +57,21 @@ class FTPBillingTest(BaseBillingTest):
def test_ftp_account_1_year_fiexed(self):
service = self.create_ftp_service()
user = self.create_ftp()
bp = timezone.now().date() + relativedelta.relativedelta(years=1)
bp = timezone.now().date() + relativedelta(years=1)
bills = service.orders.bill(billing_point=bp, fixed_point=True)
self.assertEqual(10, bills[0].get_total())
def test_ftp_account_2_year_fiexed(self):
service = self.create_ftp_service()
user = self.create_ftp()
bp = timezone.now().date() + relativedelta.relativedelta(years=2)
bp = timezone.now().date() + relativedelta(years=2)
bills = service.orders.bill(billing_point=bp, fixed_point=True)
self.assertEqual(20, bills[0].get_total())
def test_ftp_account_6_month_fixed(self):
service = self.create_ftp_service()
self.create_ftp()
bp = timezone.now().date() + relativedelta.relativedelta(months=6)
bp = timezone.now().date() + relativedelta(months=6)
bills = service.orders.bill(billing_point=bp, fixed_point=True)
self.assertEqual(5, bills[0].get_total())
@ -95,7 +96,7 @@ class FTPBillingTest(BaseBillingTest):
account = self.create_account()
service = self.create_ftp_service()
user = self.create_ftp(account=account)
first_bp = timezone.now().date() + relativedelta.relativedelta(years=2)
first_bp = timezone.now().date() + relativedelta(years=2)
bills = service.orders.bill(billing_point=first_bp, fixed_point=True)
self.assertEqual(1, service.orders.active().count())
user.delete()
@ -103,7 +104,7 @@ class FTPBillingTest(BaseBillingTest):
user = self.create_ftp(account=account)
self.assertEqual(1, service.orders.active().count())
self.assertEqual(2, service.orders.count())
bp = timezone.now().date() + relativedelta.relativedelta(years=1)
bp = timezone.now().date() + relativedelta(years=1)
bills = service.orders.bill(billing_point=bp, fixed_point=True, new_open=True)
discount = bills[0].lines.order_by('id')[0].sublines.get()
self.assertEqual(decimal.Decimal(-20), discount.total)
@ -246,7 +247,9 @@ class DomainBillingTest(BaseBillingTest):
self.assertEqual(6, bills[0].get_total())
class TrafficBillingTest(BaseBillingTest):
class BaseTrafficBillingTest(BaseBillingTest):
METRIC = 'account.resources.traffic.used'
def create_traffic_service(self):
service = Service.objects.create(
description="Traffic",
@ -255,7 +258,7 @@ class TrafficBillingTest(BaseBillingTest):
billing_period=Service.MONTHLY,
billing_point=Service.FIXED_DATE,
is_fee=False,
metric='account.resources.traffic.used',
metric=self.METRIC,
pricing_period=Service.BILLING_PERIOD,
rate_algorithm=Service.STEP_PRICE,
on_cancel=Service.NOTHING,
@ -287,7 +290,9 @@ class TrafficBillingTest(BaseBillingTest):
MonitorData.objects.create(monitor='FTPTraffic', content_object=account.user, value=value, date=date)
data = ResourceData.get_or_create(account, self.resource)
data.update()
class TrafficBillingTest(BaseTrafficBillingTest):
def test_traffic(self):
service = self.create_traffic_service()
resource = self.create_traffic_resource()
@ -297,7 +302,7 @@ class TrafficBillingTest(BaseBillingTest):
bills = service.orders.bill(commit=False)
self.assertEqual([(account, [])], bills)
# Prepay
# move into the past
delta = datetime.timedelta(days=60)
date = (timezone.now()-delta).date()
order = service.orders.get()
@ -322,10 +327,71 @@ class TrafficBillingTest(BaseBillingTest):
account1 = self.create_account()
account2 = self.create_account()
# TODO
class TrafficPrepayBillingTest(BaseTrafficBillingTest):
METRIC = "max((account.resources.traffic.used or 0) - getattr(account.miscellaneous.filter(service__name='traffic prepay').last(), 'amount', 0), 0)"
def create_prepay_service(self):
service = Service.objects.create(
description="Traffic prepay",
content_type=ContentType.objects.get_for_model(Miscellaneous),
match="miscellaneous.is_active and miscellaneous.service.name.lower() == 'traffic prepay'",
billing_period=Service.ANUAL,
billing_point=Service.FIXED_DATE,
is_fee=False,
metric="miscellaneous.amount",
pricing_period=Service.BILLING_PERIOD,
rate_algorithm=Service.STEP_PRICE,
on_cancel=Service.NOTHING, # TODO on_register == NOTHING or make on_cancel generic
payment_style=Service.PREPAY,
tax=0,
nominal_price=5
)
return service
def create_prepay(self, amount, account=None):
if not account:
account = self.create_account()
name = 'traffic prepay'
service, __ = MiscService.objects.get_or_create(name='traffic prepay', description='Traffic prepay', has_amount=True)
return Miscellaneous.objects.create(service=service, description=name, account=account, amount=amount)
def test_traffic_prepay(self):
pass
# TODO
service = self.create_traffic_service()
prepay_service = self.create_prepay_service()
account = self.create_account()
self.create_traffic_resource()
prepay = self.create_prepay(10, account=account)
self.report_traffic(account, timezone.now(), 10**9)
print prepay_service.orders.all()
# TODO metric on the current day! how to solve it consistently?
# TODO prepay doesnt allow for discount
# move into the past
# TODO with patch.object(timezone, 'now', return_value=now+relativedelta(years=1)):
delta = datetime.timedelta(days=60)
date = (timezone.now()-delta).date()
order = service.orders.get()
order.registered_on = date
order.save()
metric = order.metrics.latest()
metric.updated_on -= delta
metric.save()
bills = service.orders.bill(proforma=True)
self.assertEqual(0, bills[0].get_total())
self.report_traffic(account, date, 10**10*9)
metric = order.metrics.latest()
metric.updated_on -= delta
metric.save()
bills = service.orders.bill(proforma=True)
self.assertEqual((90-10-10)*10, bills[0].get_total())
class MailboxBillingTest(BaseBillingTest):
@ -403,7 +469,7 @@ class MailboxBillingTest(BaseBillingTest):
self.allocate_disk(mailbox, 10)
bill = service.orders.bill()[0]
self.assertEqual(0, bill.get_total())
bp = timezone.now().date() + relativedelta.relativedelta(years=1)
bp = timezone.now().date() + relativedelta(years=1)
bill = disk_service.orders.bill(billing_point=bp, fixed_point=True)[0]
self.assertEqual(90, bill.get_total())
mailbox = self.create_mailbox(account=account)
@ -421,38 +487,30 @@ class MailboxBillingTest(BaseBillingTest):
account = self.create_account()
mailbox = self.create_mailbox(account=account)
now = timezone.now()
bp = now.date() + relativedelta.relativedelta(years=1)
bp = now.date() + relativedelta(years=1)
options = dict(billing_point=bp, fixed_point=True, proforma=True, new_open=True)
self.allocate_disk(mailbox, 10)
bill = service.orders.bill(billing_point=bp, fixed_point=True, proforma=True, new_open=True)[0]
bill = service.orders.bill(**options).pop()
self.assertEqual(9*10, bill.get_total())
self.allocate_disk(mailbox, 20)
created_on = now+relativedelta.relativedelta(months=6)
order = service.orders.get()
metric = order.metrics.latest('id')
metric.created_on = created_on
metric.save()
bill = service.orders.bill(billing_point=bp, fixed_point=True, proforma=True, new_open=True)[0]
self.assertEqual(9*10*0.5 + 19*10*0.5, bill.get_total())
with freeze_time(now+relativedelta(months=6)):
self.allocate_disk(mailbox, 20)
bill = service.orders.bill(**options).pop()
total = 9*10*0.5 + 19*10*0.5
self.assertEqual(total, bill.get_total())
self.allocate_disk(mailbox, 30)
created_on = now+relativedelta.relativedelta(months=9)
order = service.orders.get()
metric = order.metrics.latest('id')
metric.created_on = created_on
metric.save()
bill = service.orders.bill(billing_point=bp, fixed_point=True, proforma=True, new_open=True)[0]
self.assertEqual(9*10*0.5 + 19*10*0.25 + 29*10*0.25, bill.get_total())
with freeze_time(now+relativedelta(months=9)):
self.allocate_disk(mailbox, 30)
bill = service.orders.bill(**options).pop()
total = 9*10*0.5 + 19*10*0.25 + 29*10*0.25
self.assertEqual(total, bill.get_total())
self.allocate_disk(mailbox, 10)
created_on = now+relativedelta.relativedelta(years=1)
order = service.orders.get()
metric = order.metrics.latest('id')
metric.created_on = created_on
metric.save()
bill = service.orders.bill(billing_point=bp, fixed_point=True, proforma=True, new_open=True)[0]
self.assertEqual(9*10*0.5 + 19*10*0.25 + 29*10*0.25, bill.get_total())
with freeze_time(now+relativedelta(years=1)):
self.allocate_disk(mailbox, 10)
bill = service.orders.bill(**options).pop()
total = 9*10*0.5 + 19*10*0.25 + 29*10*0.25
self.assertEqual(total, bill.get_total())
class JobBillingTest(BaseBillingTest):
@ -480,9 +538,9 @@ class JobBillingTest(BaseBillingTest):
def create_job(self, amount, account=None):
if not account:
account = self.create_account()
job_name = '%s.es' % random_ascii(10)
job_service, __ = MiscService.objects.get_or_create(name='job', description='Random job', has_amount=True)
return Miscellaneous.objects.create(service=job_service, description=job_name, account=account, amount=amount)
description = 'Random Job %s' % random_ascii(10)
service, __ = MiscService.objects.get_or_create(name='job', description=description, has_amount=True)
return Miscellaneous.objects.create(service=service, description=description, account=account, amount=amount)
def test_job(self):
service = self.create_job_service()
@ -499,7 +557,22 @@ class JobBillingTest(BaseBillingTest):
class PlanBillingTest(BaseBillingTest):
def create_plan_service(self):
pass
service = Service.objects.create(
description="Association membership fee",
content_type=ContentType.objects.get_for_model(Miscellaneous),
match="account.is_active and account.type == 'ASSOCIATION'",
billing_period=Service.ANUAL,
billing_point=Service.FIXED_DATE,
is_fee=True,
metric='',
pricing_period=Service.BILLING_PERIOD,
rate_algorithm=Service.STEP_PRICE,
on_cancel=Service.DISCOUNT,
payment_style=Service.PREPAY,
tax=0,
nominal_price=20
)
return service
def create_plan(self):
if not account:

View file

@ -161,7 +161,7 @@ class MonitorData(models.Model):
content_object = GenericForeignKey()
class Meta:
get_latest_by = 'date'
get_latest_by = 'id'
verbose_name_plural = _("monitor data")
def __unicode__(self):

View file

@ -288,7 +288,9 @@ class ServiceHandler(plugins.Plugin):
dsize, new_end = self.apply_compensations(order, only_beyond=True)
cprice += dsize*price
if cprice:
discounts = (('compensation', -cprice),)
discounts = (
('compensation', -cprice),
)
if new_end:
size = self.get_price_size(order.new_billed_until, new_end)
price += price*size
@ -386,7 +388,9 @@ class ServiceHandler(plugins.Plugin):
discounts = ()
dsize, new_end = self.apply_compensations(order)
if dsize:
discounts=(('compensation', -dsize*price),)
discounts=(
('compensation', -dsize*price),
)
if new_end:
order.new_billed_until = new_end
end = new_end

View file

@ -326,7 +326,7 @@ class HandlerTests(BaseTestCase):
rates = [
{'price': decimal.Decimal('0.00'), 'quantity': 2},
{'price': decimal.Decimal('9.00'), 'quantity': 28},
]
]
for rate, result in zip(rates, results):
self.assertEqual(rate['price'], result.price)
self.assertEqual(rate['quantity'], result.quantity)
@ -337,7 +337,7 @@ class HandlerTests(BaseTestCase):
rates = [
{'price': decimal.Decimal('0.00'), 'quantity': 4},
{'price': decimal.Decimal('9.00'), 'quantity': 26},
]
]
for rate, result in zip(rates, results):
self.assertEqual(rate['price'], result.price)
self.assertEqual(rate['quantity'], result.quantity)
@ -348,7 +348,7 @@ class HandlerTests(BaseTestCase):
rates = [
{'price': decimal.Decimal('0.00'), 'quantity': 6},
{'price': decimal.Decimal('9.00'), 'quantity': 24},
]
]
for rate, result in zip(rates, results):
self.assertEqual(rate['price'], result.price)
self.assertEqual(rate['quantity'], result.quantity)
@ -366,3 +366,6 @@ class HandlerTests(BaseTestCase):
lines = service.handler.generate_bill_lines(orders, account, commit=False)
print lines
print len(lines)
# TODO
# TODO test incomplete rate 1 -> nominal_price 10 -> rate

View file

@ -13,7 +13,9 @@ from .. import settings
class Apache2Backend(ServiceController):
model = 'websites.Website'
related_models = (('websites.Content', 'website'),)
related_models = (
('websites.Content', 'website'),
)
verbose_name = _("Apache 2")
def save(self, site):

View file

@ -82,7 +82,7 @@ export -f get_orchestra_dir
function print_install_requirements_help () {
cat <<- EOF
cat <<- EOF
${bold}NAME${normal}
${bold}orchetsra-admin install_requirements${normal} - Installs all Orchestra requirements using apt-get and pip
@ -157,7 +157,8 @@ function install_requirements () {
iceweasel"
PIP="${PIP} \
selenium \
xvfbwrapper"
xvfbwrapper \
freezegun"
fi
# Make sure locales are in place before installing postgres
@ -253,6 +254,7 @@ function print_install_certificate_help () {
EOF
}
function install_certificate () {
opts=$(getopt -o h -l help -- "$@") || exit 1
set -- $opts
@ -311,7 +313,6 @@ function uninstall_certificate () {
export -f uninstall_certificate
function print_install_postfix_help () {
cat <<- EOF
@ -329,7 +330,7 @@ function print_install_postfix_help () {
function install_postfix () {
opts=$(getopt -o h -l help -- "$@") || exit 1
set -- $opts
while [ $# -gt 0 ]; do
case $1 in
-h|--help) print_deploy_help; exit 0 ;;
@ -364,6 +365,7 @@ function install_postfix () {
}
export -f install_postfix
function print_uninstall_postfix_help () {
cat <<- EOF