SciPost Code Repository

Skip to content
Snippets Groups Projects
Commit 5943cb92 authored by George Katsikas's avatar George Katsikas :goat:
Browse files

add random instance faker methods

test conditional assignment offer factories
parent a37b9b64
No related branches found
No related tags found
No related merge requests found
...@@ -3,6 +3,8 @@ __license__ = "AGPL v3" ...@@ -3,6 +3,8 @@ __license__ = "AGPL v3"
import random import random
from datetime import datetime, timedelta from datetime import datetime, timedelta
from django.db.models import QuerySet
from django.db.models.base import ModelBase
from django.utils.timezone import make_aware from django.utils.timezone import make_aware
import factory import factory
...@@ -31,6 +33,25 @@ class LazyRandEnum(factory.LazyAttribute): ...@@ -31,6 +33,25 @@ class LazyRandEnum(factory.LazyAttribute):
return [random.choice(self.enum)[0] for _ in range(self.repeat)] return [random.choice(self.enum)[0] for _ in range(self.repeat)]
class LazyRandInstance(factory.LazyAttribute):
"""
Define a lazy attribute that takes a random instance from a Django model.
The first argument can be either the model class or a query set.
The second argument is the number of instances to return.
"""
def __init__(self, model_qs: ModelBase | QuerySet, repeat=1, *args, **kwargs):
self.qs = model_qs if isinstance(model_qs, QuerySet) else model_qs.objects.all()
self.repeat = repeat
super().__init__(function=self._random_instance, *args, **kwargs)
def _random_instance(self, _):
if self.repeat == 1:
return self.qs.order_by("?").first()
else:
return self.qs.order_by("?")[: self.repeat]
class LazyObjectCount(factory.LazyAttribute): class LazyObjectCount(factory.LazyAttribute):
""" """
Define a lazy attribute that returns the total number of objects of a model. Define a lazy attribute that returns the total number of objects of a model.
...@@ -97,8 +118,18 @@ class TZAwareDateAccessor: ...@@ -97,8 +118,18 @@ class TZAwareDateAccessor:
setattr(self, attr, aware_wrapper(func=getattr(parent_obj, attr))) setattr(self, attr, aware_wrapper(func=getattr(parent_obj, attr)))
def _get_random_instance(model_qs: ModelBase | QuerySet, repeat=1):
qs = model_qs if isinstance(model_qs, QuerySet) else model_qs.objects.all()
if repeat == 1:
return qs.order_by("?").first()
else:
return qs.order_by("?")[:repeat]
fake = Faker() fake = Faker()
fake.add_provider(DurationProvider) fake.add_provider(DurationProvider)
aware_date_accessor = TZAwareDateAccessor(fake) aware_date_accessor = TZAwareDateAccessor(fake)
fake.aware = aware_date_accessor fake.aware = aware_date_accessor
fake.random_instance = _get_random_instance
...@@ -117,6 +117,10 @@ class JournalFactory(factory.django.DjangoModelFactory): ...@@ -117,6 +117,10 @@ class JournalFactory(factory.django.DjangoModelFactory):
) )
self.specialties.add(*specialties) self.specialties.add(*specialties)
@factory.post_generation
def journal_alternatives(self, create, extracted, **kwargs):
self.alternative_journals.add(*fake.random_instance(Journal, 3))
class VolumeFactory(factory.django.DjangoModelFactory): class VolumeFactory(factory.django.DjangoModelFactory):
in_journal = factory.SubFactory(JournalFactory) in_journal = factory.SubFactory(JournalFactory)
......
...@@ -10,8 +10,11 @@ from .models import Preprint ...@@ -10,8 +10,11 @@ from .models import Preprint
class PreprintFactory(factory.django.DjangoModelFactory): class PreprintFactory(factory.django.DjangoModelFactory):
identifier_w_vn_nr = factory.Faker("numerify", text="####.####")
class Meta: class Meta:
model = Preprint model = Preprint
django_get_or_create = ("identifier_w_vn_nr",)
class Params: class Params:
arXiv = factory.Trait( arXiv = factory.Trait(
......
...@@ -3,10 +3,11 @@ __license__ = "AGPL v3" ...@@ -3,10 +3,11 @@ __license__ = "AGPL v3"
import factory import factory
import factory.random
from common.faker import LazyRandEnum, fake from common.faker import LazyRandEnum, fake
from ..models import EditorialAssignment from ..models.assignment import *
class EditorialAssignmentFactory(factory.django.DjangoModelFactory): class EditorialAssignmentFactory(factory.django.DjangoModelFactory):
...@@ -33,3 +34,45 @@ class EditorialAssignmentFactory(factory.django.DjangoModelFactory): ...@@ -33,3 +34,45 @@ class EditorialAssignmentFactory(factory.django.DjangoModelFactory):
start_date=self.date_invited, end_date="+10d" start_date=self.date_invited, end_date="+10d"
) )
) )
class ConditionalAssignmentOfferFactory(factory.django.DjangoModelFactory):
class Meta:
model = ConditionalAssignmentOffer
django_get_or_create = ("submission", "offered_by")
submission = factory.SubFactory("submissions.factories.SubmissionFactory")
offered_by = factory.SubFactory("scipost.factories.ContributorFactory")
offered_on = factory.LazyAttribute(
lambda self: fake.aware.date_between(
start_date=self.submission.submission_date, end_date="+60d"
)
)
offered_until = factory.LazyAttribute(
lambda self: fake.aware.date_between(
start_date=self.offered_on, end_date="+30d"
)
)
condition_type = LazyRandEnum(ConditionalAssignmentOffer.CONDITION_CHOICES)
# Add parameter to accept the offer, in which case an acceptance date is set
@factory.post_generation
def accept(self, create, extracted, **kwargs):
if extracted:
self.status = ConditionalAssignmentOffer.STATUS_ACCEPTED
self.accepted_on = fake.aware.date_between(
start_date=self.offered_on, end_date="+10d"
)
class JournalTransferOfferFactory(ConditionalAssignmentOfferFactory):
condition_type = "JournalTransfer"
condition_details = factory.LazyAttribute(
lambda self: {
"alternative_journal_id": factory.random.random.choice(
self.submission.submitted_to.alternative_journals.all()
).id
}
)
...@@ -60,6 +60,7 @@ class SubmissionFactory(factory.django.DjangoModelFactory): ...@@ -60,6 +60,7 @@ class SubmissionFactory(factory.django.DjangoModelFactory):
class Meta: class Meta:
model = Submission model = Submission
django_get_or_create = ("preprint",)
@factory.post_generation @factory.post_generation
def add_specialties(self, create, extracted, **kwargs): def add_specialties(self, create, extracted, **kwargs):
......
...@@ -111,3 +111,16 @@ class TestiThenticateReportFactory(TestCase): ...@@ -111,3 +111,16 @@ class TestiThenticateReportFactory(TestCase):
def test_can_create_ithenticate_reports(self): def test_can_create_ithenticate_reports(self):
ithenticate_report = iThenticateReportFactory() ithenticate_report = iThenticateReportFactory()
self.assertIsNotNone(ithenticate_report) self.assertIsNotNone(ithenticate_report)
# Conditional Assignment Offer
class TestConditionalAssignmentOfferFactory(TestCase):
def test_can_create_offers(self):
offer = ConditionalAssignmentOfferFactory()
self.assertIsNotNone(offer)
class TestJournalTransferOfferFactory(TestCase):
def test_can_create_offers(self):
offer = JournalTransferOfferFactory()
self.assertIsNotNone(offer)
__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
__license__ = "AGPL v3" __license__ = "AGPL v3"
from common.faker import fake
from django.test import TestCase from django.test import TestCase
# from .factories import ResubmittedSubmissionFactory from journals.models.journal import Journal
# from submissions.factories.assignment import (
# ConditionalAssignmentOfferFactory,
# class NewSubmissionStatusTest(TestCase): JournalTransferOfferFactory,
# '''Do tests to check the submission status cycle.''' )
# def test_resubmitted_submission(self): from submissions.factories.submission import SubmissionFactory
# '''New resubmission.''' from submissions.models.assignment import ConditionalAssignmentOffer
# submission = ResubmittedSubmissionFactory()
class TestJournalTransferOfferAcceptance(TestCase):
def test_accepting_offer_changes_journal(self) -> None:
offer = JournalTransferOfferFactory(
offered_until=fake.aware.date_time_this_month(
after_now=True, before_now=False
)
)
offer.accept(offer.submission.submitted_by)
# Check the conditions have been applied
alternative_journal = Journal.objects.get(
id=offer.condition_details["alternative_journal_id"]
)
self.assertEqual(offer.submission.submitted_to, alternative_journal)
class TestConditionalAssignmentOfferAcceptance(TestCase):
def setUp(self) -> None:
self.submission = SubmissionFactory()
self.offer = ConditionalAssignmentOfferFactory(
submission=self.submission,
offered_until=fake.aware.date_time_this_year(
before_now=False, after_now=True
),
condition_details={
"alternative_journal_id": self.submission.submitted_to.id
}, # Hack temporary fix
)
def test_can_accept_offer(self) -> None:
self.offer.accept(self.offer.submission.submitted_by)
self.assertEqual(self.offer.status, ConditionalAssignmentOffer.STATUS_ACCEPTED)
self.assertIsNotNone(self.offer.accepted_on)
self.assertIsNotNone(self.offer.accepted_by)
def test_finalizing_offer(self):
other_offers = ConditionalAssignmentOfferFactory.create_batch(
5, submission=self.submission
)
self.offer.accept(self.offer.submission.submitted_by)
self.offer.finalize()
# Creates an editorial assignment for the self.offering fellow
self.assertIsNotNone(
self.offer.submission.editorial_assignments.filter(to=self.offer.offered_by)
)
self.assertEqual(self.offer.submission.editor_in_charge, self.offer.offered_by)
self.assertEqual(self.offer.status, ConditionalAssignmentOffer.STATUS_FULFILLED)
# Implicitly declines all other offers
for other_offer in other_offers:
other_offer.refresh_from_db()
self.assertEqual(
other_offer.status,
ConditionalAssignmentOffer.STATUS_DECLINED,
)
class TestConditionalAssignmentOfferAcceptanceFailure(TestCase):
def setUp(self) -> None:
self.submission = SubmissionFactory()
def test_cannot_accept_expired_offer(self):
with self.assertRaises(ValueError):
offer = ConditionalAssignmentOfferFactory(
offered_until=fake.aware.date_time_this_year(
before_now=True, after_now=False
),
condition_details={
"alternative_journal_id": self.submission.submitted_to.id
}, # Hack temporary fix
)
offer.accept(offer.submission.submitted_by)
def test_cannot_accept_already_accepted_offer(self):
offer = ConditionalAssignmentOfferFactory(
offered_until=fake.aware.date_time_this_year(
before_now=False, after_now=True
),
condition_details={
"alternative_journal_id": self.submission.submitted_to.id
}, # Hack temporary fix
)
offer.accept(offer.submission.submitted_by)
with self.assertRaises(ValueError):
offer.accept(offer.submission.submitted_by)
def test_cannot_accept_declined_offer(self):
offer = ConditionalAssignmentOfferFactory(
offered_until=fake.aware.date_time_this_year(
before_now=False, after_now=True
),
status=ConditionalAssignmentOffer.STATUS_DECLINED,
condition_details={
"alternative_journal_id": self.submission.submitted_to.id
}, # Hack temporary fix
)
with self.assertRaises(ValueError):
offer.accept(offer.submission.submitted_by)
def test_cannot_accept_later_identical_offer(self):
offer = ConditionalAssignmentOfferFactory(
offered_until=fake.aware.date_time_this_year(
before_now=False, after_now=True
),
condition_details={
"alternative_journal_id": self.submission.submitted_to.id
}, # Hack temporary fix
)
later_offer = ConditionalAssignmentOfferFactory(
submission=offer.submission,
offered_on=fake.aware.date_time_between(
start_date=offer.offered_on, end_date="+30d"
),
offered_until=offer.offered_until,
condition_type=offer.condition_type,
condition_details=offer.condition_details,
)
with self.assertRaises(ValueError):
later_offer.accept(self.submission.submitted_by)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment