123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- import datetime
- from django.test import TestCase
- from django.core.exceptions import ValidationError
- from ..models import (
- Cost, CostUse, Document, Good, GoodUse, Service, ServiceUse)
- THREE_YEARS = datetime.timedelta(days=365*3)
- class ServiceTests(TestCase):
- def setUp(self):
- self.doc = Document.objects.create(name='budget')
- self.electricity_cost = Cost.objects.create(
- name='electricity',
- price=10,
- document=self.doc,
- )
- self.server = Good.objects.create(
- name="Computer",
- price=10,
- document=self.doc,
- provisioning_duration=THREE_YEARS,
- )
- def test_get_prices_zero(self):
- s = Service.objects.create(name='Foo', document=self.doc)
- self.assertEqual(s.get_prices(), {
- 'total_recurring_price': 0,
- 'total_goods_value_share': 0,
- 'unit_recurring_price': 0,
- 'unit_goods_value_share': 0,
- 'unit_recurring_price': 0,
- 'unit_consolidated_cost': 0,
- 'unit_staggered_goods_share': 0,
- })
- def test_get_prices_w_costs(self):
- s = Service.objects.create(name='Foo', document=self.doc)
- CostUse.objects.create(
- service=s, resource=self.electricity_cost, share=0.4)
- self.assertEqual(s.get_prices(), {
- 'total_recurring_price': 10,
- 'unit_recurring_price': 0,
- 'unit_goods_value_share': 0,
- 'total_goods_value_share': 0,
- 'unit_staggered_goods_share': 0.0,
- 'unit_consolidated_cost': 0,
- })
- s.subscriptions_count = 2
- s.save()
- self.assertEqual(s.get_prices(), {
- 'total_recurring_price': 10,
- 'total_goods_value_share': 0,
- 'unit_recurring_price': 5,
- 'unit_goods_value_share': 0,
- 'unit_staggered_goods_share': 0,
- 'unit_consolidated_cost': 5.0,
- })
- def test_get_prices_w_goods(self):
- s = Service.objects.create(
- name='Foo', document=self.doc, subscriptions_count=0)
- GoodUse.objects.create(
- service=s, resource=self.server, share=0.4)
- self.assertEqual(s.get_prices(), {
- 'total_recurring_price': 10/(365*3)*365.25/12,
- 'unit_recurring_price': 0,
- 'unit_goods_value_share': 0,
- 'total_goods_value_share': 10,
- 'unit_consolidated_cost': 0.0,
- 'unit_staggered_goods_share': 0.0,
- })
- s.subscriptions_count = 2
- s.save()
- total_recurring_price = 10/(365*3)*365.25/12
- self.assertEqual(s.get_prices(), {
- 'total_recurring_price': total_recurring_price,
- 'total_goods_value_share': 10,
- 'unit_recurring_price': total_recurring_price/2,
- 'unit_goods_value_share': 5,
- 'unit_staggered_goods_share': 5/36,
- 'unit_consolidated_cost': total_recurring_price/2 + 5/36,
- })
- def test_compare_service(self):
- s_first = Service.objects.create(
- name='Foo', document=self.doc, subscriptions_count=3)
- # The first service has no cost/goods associated
- s_second = Service.objects.create(
- name='Bar', document=self.doc, subscriptions_count=2)
- GoodUse.objects.create(
- service=s_second, resource=self.server, share=0.4)
- total_recurring_price = 10/(365*3)*365.25/12
- self.assertEqual(s_second.compare(s_first), {
- 'total_recurring_price': total_recurring_price,
- 'total_goods_value_share': 10,
- 'unit_recurring_price': total_recurring_price/2,
- 'unit_goods_value_share': 5,
- 'unit_staggered_goods_share': 5/36,
- 'unit_consolidated_cost': total_recurring_price/2 + 5/36,
- 'subscriptions_count': -1,
- })
- def test_similar(self):
- other_doc = Document.objects.create(name='other budget')
- a = Service.objects.create(
- name='Foo', document=self.doc, subscriptions_count=3)
- b = Service.objects.create(
- name='Foo', document=other_doc, subscriptions_count=3)
- c = Service.objects.create(
- name='Bar', document=other_doc, subscriptions_count=3)
- similars = Service.objects.similar_to(a)
- self.assertEqual(similars.count(), 1)
- self.assertEqual(similars.first(), b)
- class AbstractUseTests(TestCase):
- """ Testing AbstractUseTests through CostUse
- """
- def setUp(self):
- self.doc = Document.objects.create(name='budget')
- self.hosting_service = Service.objects.create(
- name='Physical hosting', document=self.doc)
- self.mailbox_service = Service.objects.create(
- name='Mailbox', document=self.doc)
- self.electricity_cost = Cost.objects.create(
- name='electricity',
- price=10,
- document=self.doc,
- capacity_unit='A',
- total_capacity=4,
- )
- self.carrier_connection = Cost.objects.create(
- name='carrier connection',
- price=100,
- document=self.doc,
- )
- def test_can_add_service_share(self):
- use = CostUse(
- service=self.hosting_service,
- resource=self.electricity_cost,
- share=0.4)
- use.full_clean()
- use.save()
- def test_can_add_service_share_with_custom_unity(self):
- use = CostUse(
- service=self.hosting_service,
- resource=self.electricity_cost,
- share=2) # means 2 Amps
- self.hosting_service.subscriptions_count = 2
- self.hosting_service.save()
- use.full_clean()
- use.save()
- self.assertEqual(use.share, 2.0)
- self.assertEqual(use.real_share(), 4.0)
- self.assertEqual(use.cost_share(), 10)
- self.assertEqual(use.unit_cost_share(), 5)
- def test_cannot_add_excess_share_one(self):
- use = CostUse(
- service=self.hosting_service,
- resource=self.electricity_cost,
- share=40.1)
- with self.assertRaises(ValidationError):
- use.full_clean()
- use.save()
- def test_add_several_service_share(self):
- u1 = CostUse(
- service=self.hosting_service,
- resource=self.electricity_cost,
- share=0.4)
- u1.full_clean()
- u1.save()
- u2 = CostUse(
- service=self.mailbox_service,
- resource=self.electricity_cost,
- share=0.6)
- u2.full_clean()
- u2.save()
- def test_add_several_service_share_excessive_sum(self):
- u1 = CostUse(
- service=self.hosting_service,
- resource=self.electricity_cost,
- share=3)
- u1.full_clean()
- u1.save()
- u2 = CostUse(
- service=self.mailbox_service,
- resource=self.electricity_cost,
- share=1.1)
- # Would be 4.1 out of 4 amp...
- with self.assertRaises(ValidationError):
- u2.full_clean()
- u2.save()
- def test_modify_service_share_no_error(self):
- u1 = CostUse(
- service=self.hosting_service,
- resource=self.electricity_cost,
- share=1)
- u1.full_clean()
- u1.save()
- u1.full_clean()
- u1.save()
- def test_real_shares(self):
- u1 = CostUse.objects.create(
- service=self.hosting_service,
- resource=self.electricity_cost,
- share=1.6)
- u2 = CostUse.objects.create(
- service=self.hosting_service,
- resource=self.electricity_cost,
- share=0.6)
- self.assertEqual(u1.real_share() + u2.real_share(), 4)
- self.assertEqual(u1.share/u2.share, u1.real_share()/u2.real_share())
- def test_unit_value_share(self):
- self.mailbox_service.subscriptions_count = 2
- self.mailbox_service.share = 0.5
- self.hosting_service.save()
- self.hosting_service.subscriptions_count = 1
- self.hosting_service.share = 0.5
- self.hosting_service.save()
- mailbox_use = CostUse.objects.create(
- service=self.mailbox_service,
- resource=self.electricity_cost,
- share=2)
- hosting_use = CostUse.objects.create(
- service=self.hosting_service,
- resource=self.electricity_cost,
- share=2)
- self.assertEqual(mailbox_use.value_share(), 5)
- self.assertEqual(mailbox_use.unit_value_share(), 2.5)
- self.assertEqual(hosting_use.value_share(), 5)
- self.assertEqual(hosting_use.unit_value_share(), 5)
- def test_used(self):
- CostUse.objects.create(
- service=self.mailbox_service,
- resource=self.electricity_cost,
- share=0.5)
- self.assertEqual(self.electricity_cost.used(), 0.5)
- self.assertEqual(self.electricity_cost.unused(), 3.5)
- def test_service_using_service(self):
- """
- Wifi+VPN is a service, but using VPN access
- So there is a service using another service
- """
- vpn_service = Service.objects.create(
- name="VPN",
- document=self.doc,
- subscriptions_count=20, # includes wifi+vpn subscribers
- reusable=True,
- )
- # both should be auto-set
- self.assertEqual(vpn_service.capacity_unit, 'services')
- self.assertEqual(vpn_service.total_capacity, 20)
- wifi_service = Service.objects.create(
- name="Wifi, via VPN",
- document=self.doc,
- subscriptions_count=2,
- reusable=True,
- )
- self.assertEqual(vpn_service.capacity_unit, 'services')
- # To simplify, VPN is only using electricity
- CostUse.objects.create(
- service=vpn_service,
- resource=self.electricity_cost,
- share=0.5, # Amp
- )
- # Wifi is using VPN + a carrier connection
- wifi_vpn_use = ServiceUse.objects.create(
- service=wifi_service,
- resource=vpn_service,
- share=2,
- )
- CostUse.objects.create(
- service=wifi_service,
- resource=self.carrier_connection,
- share=1, # 100%
- )
- self.assertEqual(wifi_vpn_use.share, 0.5*4*10/20*2)
- self.assertEqual(wifi_vpn_use.unit_share(), 0.5*4*10/20)
- # VPN this is the only service using electricity
- self.assertEqual(wifi_vpn_use.unit_real_share(), 10)
- # VPN is now using some gear, with deprecation provisioning
- hosting_access_fee = Good.objects.create(
- name='hosting access fee', price=360,
- provisioning_duration=THREE_YEARS, document=self.doc)
- GoodUse.objects.create(
- service=vpn_service, resource=hosting_access_fee, share=2)
- self.assertEqual(
- wifi_service.get_prices()['total_goods_value_share'], 36)
- self.assertEqual(
- wifi_service.get_prices()['unit_goods_value_share'], 18)
- def test_service_using_non_usable_service(self):
- serva = Service.objects.create(
- name='A', document=self.doc,
- subscriptions_count=4,
- reusable=False,
- )
- with self.assertRaises(ValidationError):
- su = ServiceUse(
- service=self.mailbox_service,
- resource=serva,
- share=1,
- )
- su.full_clean()
- su.save()
- def test_service_using_cyclic_service(self):
- """ We should not save any service dependency building a cycle
- """
- a = Service.objects.create(
- name='a', document=self.doc,
- reusable=True,
- )
- b = Service.objects.create(
- name='b', document=self.doc,
- reusable=True,
- )
- c = Service.objects.create(
- name='c', document=self.doc,
- reusable=True,
- )
- def create_clean(user, used):
- new_use = ServiceUse(service=user, resource=used, share=1)
- new_use.full_clean()
- new_use.save()
- create_clean(a, b)
- with self.assertRaises(ValidationError):
- create_clean(b, a)
- create_clean(b, c)
- with self.assertRaises(ValidationError):
- create_clean(c, a)
- class TestDocuments(TestCase):
- fixtures = ['full_example.yaml']
- _all_models = [Document, Cost, Good, Service, GoodUse, CostUse, ServiceUse]
- def _count(self):
- return [i.objects.count() for i in self._all_models]
- def test_copy(self):
- initial_counts = self._count()
- old_doc = Document.objects.first()
- new_doc = old_doc.copy()
- self.assertNotEqual(new_doc.pk, old_doc.pk)
- self.assertEqual(self._count(), [i*2 for i in initial_counts])
- old_doc.delete()
- self.assertEqual(self._count(), initial_counts)
- def test_compare(self):
- doc1 = Document.objects.create(name='a budget')
- doc2 = Document.objects.create(name='a budget')
- Service.objects.create(
- name='Foo', document=doc2, subscriptions_count=3)
- Service.objects.create(
- name='Bar', document=doc2, subscriptions_count=3)
- Service.objects.create(
- name='Bar', document=doc1, subscriptions_count=3)
- comparison = doc2.compare(doc1)
- self.assertEqual(len(comparison['services']), 2)
- self.assertIsNone(comparison['services'][0]['other_service'])
- self.assertIsNotNone(comparison['services'][1]['other_service'])
|