Skip to content

Commit

Permalink
Merge pull request #265 from SELab-2/backend_testen
Browse files Browse the repository at this point in the history
Backend testen
  • Loading branch information
sPAICEcake authored May 20, 2024
2 parents 9849628 + 6c4a6c2 commit 91b2f43
Show file tree
Hide file tree
Showing 27 changed files with 521 additions and 128 deletions.
Binary file modified .coverage
Binary file not shown.
1 change: 0 additions & 1 deletion api/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ def __call__(self, request):


class DisableCSRFMiddleware(object):

def __init__(self, get_response):
self.get_response = get_response

Expand Down
4 changes: 0 additions & 4 deletions api/models/indiening.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,6 @@ def __str__(self):
return str(self.indiening_id)

def save(self, *args, **kwargs):
# First save to generate the indiening_id if it doesn't exist
if not self.indiening_id:
super(Indiening, self).save(*args, **kwargs)

# Update the bestand path if it's still using the temporary path
if "temp" in self.bestand.name:
old_file = self.bestand
Expand Down
6 changes: 3 additions & 3 deletions api/models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class Project(models.Model):
Standaard ingesteld op 20.
max_groep_grootte (IntegerField): Een veld voor het instellen van de max grootte van de groep voor het project.
Standaard ingesteld op 1.
student_groep (BooleanField): Een veld om aan te geven of het een individueel project is of niet.
student_groep (BooleanField): Een veld om aan te geven of de studenten hun eigen groep mogen kiezen.
Standaard ingesteld of False.
zichtbaar (BooleanField): Een veld om aan te geven of het project zichtbaar is of niet.
Standaard ingesteld op True.
Expand All @@ -57,8 +57,8 @@ class Project(models.Model):
vak = models.ForeignKey(Vak, on_delete=models.CASCADE)
deadline = models.DateTimeField(null=True, blank=True)
extra_deadline = models.DateTimeField(null=True, blank=True)
max_score = models.IntegerField(default=20)
max_groep_grootte = models.IntegerField(default=1)
max_score = models.PositiveSmallIntegerField(default=20)
max_groep_grootte = models.PositiveSmallIntegerField(default=1)
student_groep = models.BooleanField(default=False, blank=True)
zichtbaar = models.BooleanField(default=True, blank=True)
gearchiveerd = models.BooleanField(default=False, blank=True)
Expand Down
2 changes: 1 addition & 1 deletion api/models/score.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Score(models.Model):
"""

score_id = models.AutoField(primary_key=True)
score = models.SmallIntegerField()
score = models.PositiveSmallIntegerField()
indiening = models.ForeignKey("Indiening", on_delete=models.CASCADE)

def __str__(self):
Expand Down
2 changes: 1 addition & 1 deletion api/models/vak.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class Vak(models.Model):

vak_id = models.AutoField(primary_key=True)
naam = models.CharField(max_length=100)
jaartal = models.IntegerField(default=date.today().year)
jaartal = models.PositiveSmallIntegerField(default=date.today().year)
gearchiveerd = models.BooleanField(default=False, blank=True)
studenten = models.ManyToManyField(
"Gebruiker", related_name="vak_gebruikers", blank=True
Expand Down
7 changes: 4 additions & 3 deletions api/serializers/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ def update(self, instance, validated_data):
Returns:
Project: Het bijgewerkte project.
"""
validated_data.pop("max_groep_grootte")
validated_data.pop("project_groep")
validated_data.pop("max_groep_grootte", instance.max_groep_grootte)

deadline = validated_data.pop("deadline", instance.deadline)
extra_deadline = validated_data.pop("extra_deadline", instance.extra_deadline)
Expand Down Expand Up @@ -103,7 +102,9 @@ def create_groepen(instance):
except Exception:
pass
else:
for _ in range(len(instance.vak.studenten.all())//instance.max_groep_grootte + 1):
for _ in range(
len(instance.vak.studenten.all()) // instance.max_groep_grootte + 1
):
try:
serializer = GroepSerializer(
data={"studenten": [], "project": instance.project_id}
Expand Down
6 changes: 5 additions & 1 deletion api/serializers/vak.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,11 @@ def add_students_to_group(instance):

else:
groepen = Groep.objects.filter(project=project.project_id)
nieuwe_groepen = len(instance.studenten.all())//project.max_groep_grootte + 1 - len(groepen)
nieuwe_groepen = (
len(instance.studenten.all()) // project.max_groep_grootte
+ 1
- len(groepen)
)
for _ in range(nieuwe_groepen):
try:
serializer = GroepSerializer(
Expand Down
15 changes: 2 additions & 13 deletions api/tests/factories/indiening.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import factory
from api.models.indiening import Indiening, IndieningBestand
from api.models.indiening import Indiening
from factory.django import DjangoModelFactory
from factory import SubFactory
from .groep import GroepFactory
Expand All @@ -23,16 +23,5 @@ class Meta:
)
status = factory.Faker("boolean")
result = factory.Faker("paragraph")
artefacten = None

indiening_bestanden = factory.RelatedFactory(
"api.tests.factories.indiening.IndieningBestandFactory", "indiening"
)


class IndieningBestandFactory(DjangoModelFactory):
class Meta:
model = IndieningBestand

indiening = SubFactory(IndieningFactory)
bestand = FileField(filename="test.txt", data=b"file content")
artefacten = None
1 change: 1 addition & 0 deletions api/tests/factories/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ class Meta:
)
max_score = factory.Faker("random_int", min=10, max=100)
max_groep_grootte = factory.Faker("random_int", min=1, max=5)
student_groep = factory.Faker("boolean")
zichtbaar = factory.Faker("boolean")
gearchiveerd = factory.Faker("boolean")
3 changes: 1 addition & 2 deletions api/tests/factories/score.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,5 @@ class Meta:
@classmethod
def _create(cls, model_class, *args, **kwargs):
indiening = kwargs.pop("indiening")
max_score = indiening.groep.project.max_score
kwargs["score"] = random.randint(0, max_score)
kwargs["score"] = random.randint(0, indiening.groep.project.max_score)
return super()._create(model_class, indiening=indiening, *args, **kwargs)
12 changes: 12 additions & 0 deletions api/tests/factories/template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import factory
from factory.django import FileField
from api.models.template import Template
from api.tests.factories.gebruiker import UserFactory


class TemplateFactory(factory.django.DjangoModelFactory):
class Meta:
model = Template

user = factory.SubFactory(UserFactory)
bestand = FileField(filename="template.txt", data=b"file content")
132 changes: 115 additions & 17 deletions api/tests/models/test_indiening.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
from django.test import TestCase
from django.core.files.uploadedfile import SimpleUploadedFile
from api.tests.factories.indiening import IndieningFactory, IndieningBestandFactory
from api.tests.factories.indiening import IndieningFactory
from api.models.indiening import upload_to
from unittest.mock import patch, MagicMock, call
from api.models.indiening import send_indiening_confirmation_mail
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import os


class IndieningModelTest(TestCase):
def setUp(self):
@patch("api.models.indiening.send_indiening_confirmation_mail")
def setUp(self, mock_send_mail):
self.indiening = IndieningFactory.create()

def test_str_method(self):
Expand All @@ -20,30 +25,123 @@ def test_tijdstip(self):
def test_status(self):
self.assertIsNotNone(self.indiening.status)

def test_indiening_bestanden(self):
self.assertEqual(self.indiening.indiening_bestanden.count(), 1)

def test_upload_to(self):
filename = "test_indiening.txt"
expected_path = (
f"data/indieningen/indiening_{self.indiening.indiening_id}/{filename}"
)
self.assertEqual(upload_to(self.indiening, filename), expected_path)

def test_artefacten(self):
self.assertIsNotNone(self.indiening.artefacten)

def test_result(self):
self.assertIsNotNone(self.indiening.result)

def test_bestand(self):
self.assertIsNotNone(self.indiening.bestand)

@patch("smtplib.SMTP_SSL")
@patch("ssl.create_default_context")
def test_send_indiening_confirmation_mail(
self, mock_create_default_context, mock_smtp
):
indiening = self.indiening
project = indiening.groep.project

smtp_server_address = "smtp.gmail.com"
smtp_port = 465
mail_username = os.environ.get("MAIL_USERNAME")
mail_app_password = os.environ.get("MAIL_APP_PASSWORD")
indiening_status = {
-1: "heeft niet alle testen geslaagd.",
0: "wordt nog getest...",
1: "heeft alle testen geslaagd!",
}
project_url = f"https://sel2-4.ugent.be/course/{project.vak.vak_id}/assignment/{project.project_id}"
indiening_url = f"https://sel2-4.ugent.be/course/{project.vak.vak_id}/assignment/ \
{project.project_id}/submission/{indiening.indiening_id}"

# Setup the mock SMTP_SSL object
mock_smtp_instance = MagicMock()
mock_smtp.return_value.__enter__.return_value = mock_smtp_instance

# Call the function
send_indiening_confirmation_mail(indiening)

# Check that create_default_context was called once
assert mock_create_default_context.call_count == 1

class IndieningBestandModelTest(TestCase):
def setUp(self):
self.indiening_bestand = IndieningBestandFactory.create(
bestand=SimpleUploadedFile("file.txt", b"file_content")
# Check that SMTP_SSL was called with the correct arguments
assert mock_smtp.call_count == indiening.groep.studenten.count()
mock_smtp.assert_has_calls(
[
call(
smtp_server_address,
smtp_port,
context=mock_create_default_context.return_value,
)
]
* indiening.groep.studenten.count()
)

def test_str_method(self):
self.assertEqual(
str(self.indiening_bestand), str(self.indiening_bestand.bestand.name)
# Check that login was called with the correct arguments
mock_smtp_instance.login.assert_called_with(mail_username, mail_app_password)

# Check that sendmail was called once for each student
assert (
mock_smtp_instance.sendmail.call_count == indiening.groep.studenten.count()
)

def test_indiening(self):
self.assertIsNotNone(self.indiening_bestand.indiening)
# Check that sendmail was called with the correct arguments
for student in indiening.groep.studenten.all():
subject = "Indieningsontvangst"

def test_bestand(self):
self.assertIsNotNone(self.indiening_bestand.bestand)
email = MIMEMultipart("alternative")
email["Subject"] = subject
email["From"] = mail_username
email["To"] = student.user.email

plain_text = f"""
Beste {student.user.first_name} {student.user.last_name},
Dit is een bevestiging dat uw indiening voor het project {project.titel} is ontvangen.
De indiening {indiening_status[indiening.status]}.
"""

html_text = f"""
<html>
<body>
<p>Beste {student.user.first_name} {student.user.last_name}</p>
<p>Dit is een bevestiging dat uw indiening voor het project \
<a href="{project_url}">{project.titel}</a> is ontvangen.</p>
<p>De <a href="{indiening_url}">indiening</a> {indiening_status[indiening.status]}</p>
</body>
</html>
"""

email.attach(MIMEText(plain_text, "plain"))
email.attach(MIMEText(html_text, "html"))

call_args_list = mock_smtp_instance.sendmail.call_args_list
for mock_call in call_args_list:
(
sent_mail_username,
sent_student_email,
sent_email_content,
) = mock_call.args
assert sent_mail_username == mail_username
assert sent_student_email == student.user.email
assert subject in sent_email_content
assert (
f"Beste {student.user.first_name} {student.user.last_name}"
in sent_email_content
)
assert (
f"Dit is een bevestiging dat uw indiening voor het project {project.titel} is ontvangen."
in sent_email_content
)
assert (
f"De indiening {indiening_status[indiening.status]}"
in sent_email_content
)
4 changes: 3 additions & 1 deletion api/tests/models/test_score.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from django.test import TestCase
from api.tests.factories.score import ScoreFactory
from api.tests.factories.indiening import IndieningFactory
from unittest.mock import patch


class ScoreModelTest(TestCase):
def setUp(self):
@patch("api.models.indiening.send_indiening_confirmation_mail")
def setUp(self, mock_send_mail):
self.indiening = IndieningFactory.create()
self.score = ScoreFactory.create(indiening=self.indiening)

Expand Down
21 changes: 21 additions & 0 deletions api/tests/models/test_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from django.test import TestCase
from api.tests.factories.template import TemplateFactory
from api.models.template import Template
from api.models.template import upload_to


class TemplateModelTest(TestCase):
def setUp(self):
self.template = TemplateFactory.create()

def test_template_creation(self):
self.assertIsInstance(self.template, Template)
self.assertEqual(Template.objects.count(), 1)

def test_template_str(self):
self.assertEqual(str(self.template), self.template.bestand.name)

def test_upload_to(self):
filename = "test_template.txt"
expected_path = f"data/templates/gebruiker_{self.template.user.id}/{filename}"
self.assertEqual(upload_to(self.template, filename), expected_path)
Loading

0 comments on commit 91b2f43

Please sign in to comment.