Skip to content

Commit

Permalink
Merge pull request #142 from tesla-ce/add_tests
Browse files Browse the repository at this point in the history
Add tests
  • Loading branch information
rogergithub3 authored Jul 28, 2023
2 parents 07b8d07 + 0700b8f commit 8d0fd3e
Show file tree
Hide file tree
Showing 14 changed files with 172 additions and 13 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

!src/tesla_ce/lib
!src/tesla_ce/lib/deploy
!src/tesla_ce/lib/webhook

# User-specific stuff
.idea/**/workspace.xml
Expand Down
2 changes: 1 addition & 1 deletion src/tesla_ce/apps/api/v2/serializers/admin/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class Meta:
model = Provider
fields = ['id', 'instrument_id', 'instrument', 'name', 'queue', 'description', 'url', 'version', 'acronym',
'allow_validation', 'inverted_polarity', 'image', 'has_service', 'service_port', 'options_schema',
'options', 'credentials', 'enabled', 'validation_active']
'options', 'credentials', 'enabled', 'validation_active', 'warning_below', 'alert_below']

def validate(self, attrs):
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ def update(self, instance, validated_data):
new_instance.audit.save('{}__audit.json'.format(new_instance.request.data.name),
ContentFile(simplejson.dumps(new_instance.audit_data).encode('utf-8')))

'''
# If all the providers reported their results, launch summarise task
if RequestProviderResult.objects.filter(Q(status=0) | Q(status=7),
request_id=new_instance.request_id,
Expand All @@ -62,4 +63,6 @@ def update(self, instance, validated_data):
instance.request.id,
new_instance.provider.instrument_id,
))
'''
return new_instance

10 changes: 10 additions & 0 deletions src/tesla_ce/lib/config/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,16 @@ class Config:
('admin_user', 'Administrator username', 'str', 'admin', None, True),
('admin_password', 'Administrator password', 'str', None, None, True),
('admin_email', 'Administrator email', 'str', None, None, True),
)),
('tpt_service', 'TeSLA TPT Service configuration.', (
('api_secret', 'API secret shared with TeSLA CE API', 'str', None, None, True),
('db_password', 'Database password', 'str', None, None, True),
('db_user', 'Database user', 'str', 'tpt_user', None, True),
('db_address', 'Database address', 'str', 'localhost', None, True),
('db_database', 'Database name', 'str', 'tpt_db', None, True),
('db_port', 'Database port', 'int', 5432, None, True),
('db_schema', 'Database schema', 'str', 'tpt_schema', None, True),
('db_engine', 'Database engine', 'str', 'postgresql+psycopg2', None, True)
))
)

Expand Down
2 changes: 1 addition & 1 deletion src/tesla_ce/lib/data/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.7
1.0.8
16 changes: 16 additions & 0 deletions src/tesla_ce/lib/webhook/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright (c) 2020 Xavier Baró
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
"""Webhook Package"""
from .process import *
32 changes: 32 additions & 0 deletions src/tesla_ce/lib/webhook/process.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import json
import simplejson
from django.core.files.base import ContentFile
from tesla_ce.models.provider import Provider
from tesla_ce.models.webhooks import WebhookMessage
from tesla_ce.models.request import Request
from tesla_ce.models.request_provider_result import RequestProviderResult


def process_webhook_message(message_id, provider_id):
webhook_message = WebhookMessage.objects.get(pk=message_id)
provider = Provider.objects.get(pk=provider_id)

if provider.acronym == 'tpt':
process_webhook_message_tpt(webhook_message, provider)


def process_webhook_message_tpt(webhook_message, provider):
body = json.loads(webhook_message.body)

if body['action'] == 'UPDATE_RESULT':
request = Request.objects.get(pk=body['request_id'])
request_provider_result = RequestProviderResult.objects.get(provider=provider, request=request)
request_provider_result.result = float(body['result'])
request_provider_result.audit_data = body['audit_data']
# status processed
request_provider_result.status = 1
request_provider_result.code = body['code']
request_provider_result.audit.save('{}__audit.json'.format(request_provider_result.request.data.name),
ContentFile(simplejson.dumps(request_provider_result.audit_data).encode('utf-8')))

request_provider_result.save()
14 changes: 13 additions & 1 deletion src/tesla_ce/management/commands/remote_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ def custom_handle(self):
'migrate_database',
'collect_static',
'load_fixtures',
'create_superuser'
'create_superuser',
'register_tpt_webhook'
]

status = {"status": False, "info": {}}
Expand Down Expand Up @@ -190,5 +191,16 @@ def custom_handle(self):
except TeslaDatabaseException as exc:
status['status'] = False
status['info'] = str(exc)
elif command in ['register_tpt_webhook']:
try:
name = 'tpt'
client_header = 'TESLA-TPT-METHOD'
id_header = 'TESLA-TPT-MESSAGE-ID'
credentials = "{\"secret\": \""+self.client.config.config.get('tpt_service_api_secret')+"\"}"
provider_info = self.client.register_webhook(name, client_header, id_header, credentials)
status['status'] = True
except Exception as err:
status['status'] = False
status['info'] = str(err)

self.report_remote_result(status=status)
1 change: 1 addition & 0 deletions src/tesla_ce/models/enrolment_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def auto_delete_file_on_delete(sender, instance, **kwargs):
when corresponding `FieldField` object is deleted.
"""
if instance.data:
# todo: remove .valid and .error associated files
try:
instance.data.delete(save=False)
except:
Expand Down
12 changes: 10 additions & 2 deletions src/tesla_ce/models/learner.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,18 @@ def delete_unused_enrolments(self):
Delete unused enrolments for this learner
:return:
"""
# todo: optimize this
for enrolment in self.enrolment_set.all():
delete = True
for request in self.request_set.all():
if enrolment.provider.instrument not in request.instruments:
enrolment.delete()
if enrolment.provider.instrument in request.instruments.all():
delete = False
break
if delete:
for model_sample in enrolment.model_samples.all():
model_sample.delete()

enrolment.delete()

@receiver(models.signals.post_delete, sender=Learner)
def auto_delete_folders_on_delete(sender, instance, **kwargs):
Expand Down
1 change: 1 addition & 0 deletions src/tesla_ce/models/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def auto_delete_file_on_delete(sender, instance, **kwargs):
when corresponding `FieldField` object is deleted.
"""
if instance.data:
# todo: remove .valid and .error associated files
try:
instance.data.delete(save=False)
except:
Expand Down
12 changes: 12 additions & 0 deletions src/tesla_ce/models/request_provider_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from django.db import models
from django.dispatch import receiver
from django.db import transaction
from django.db.models import Q
from django.utils.translation import gettext_lazy as _

from .base_model import BaseModel
Expand Down Expand Up @@ -121,6 +122,17 @@ def save(self, force_insert=False, force_update=False, using=None, update_fields
setattr(h4, bin, 1)
h4.save()

# If all the providers reported their results, launch summarise task
if RequestProviderResult.objects.filter(Q(status=0) | Q(status=7),
request_id=self.request_id,
provider__instrument=self.provider.instrument
).count() == 0:
from ..tasks.requests.verification import create_verification_summary
create_verification_summary.apply_async((
self.request.id,
self.provider.instrument_id,
))


@receiver(models.signals.post_delete, sender=RequestProviderResult)
def auto_delete_file_on_delete(sender, instance, **kwargs):
Expand Down
18 changes: 17 additions & 1 deletion src/tesla_ce/tasks/reports/results.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,12 +180,27 @@ def update_learner_activity_instrument_report(self, learner_id, activity_id, ins

# Compute the final alert levels from result codes
code_result = results_qs.filter(status=1).aggregate(Max('code'), Avg('result'))

if code_result['code__max'] is None:
code_result['code__max'] = 2 # Warning

if code_result['result__avg'] is None:
code_result['result__avg'] = 0

instrument_report.result = round(code_result['result__avg'] * 100)
instrument_report.confidence = round(results_qs.filter(status=1).count() / results_qs.count() * 100)
if results_qs.count() != 0:
instrument_report.confidence = round(results_qs.filter(status=1).count() / results_qs.count() * 100)
else:
instrument_report.confidence = 0

code = code_result['code__max']
if code > 0:
# Unless the code is 0 (PENDING), move to the alerts scale
code += 1

if instrument_report.confidence < 60:
code = max(code, 2) # Warning

# Update levels where this instrument applies
if instrument_report.instrument.identity:
instrument_report.identity_level = code
Expand All @@ -210,6 +225,7 @@ def update_learner_activity_instrument_report(self, learner_id, activity_id, ins
'request__requestproviderresult__provider_id',
flat=True).distinct()
).aggregate(Min('percentage'))['percentage__min'] * 100)

instrument_report.save()

# Update the audit data
Expand Down
61 changes: 54 additions & 7 deletions src/tesla_ce/tasks/requests/verification.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,19 +144,66 @@ def create_verification_summary(self, request_id, instrument_id):
Summarize request verification
:param request_id: Request ID
:type request_id: int
:param request_id: Instrument ID
:type request_id: int
:param instrument_id: Instrument ID
:type instrument_id: int
"""
try:
result = models.RequestResult.objects.get(request_id=request_id, instrument_id=instrument_id)
except models.RequestResult.DoesNotExist:
result = models.RequestResult.objects.create(request_id=request_id, instrument_id=instrument_id,
code=0, status=0)

res_values = models.RequestProviderResult.objects.filter(request_id=request_id,
provider__instrument_id=instrument_id,
status=1
).aggregate(Max('result'), Max('code'))

instrument_provider = models.RequestProviderResult.objects.filter(
request_id=request_id,
provider__instrument_id=instrument_id,
status=1
).values('provider_id').distinct().values_list('provider_id', flat=True)

alert_level = 0
for provider_id in instrument_provider:
provider = models.Provider.objects.get(id=provider_id)

if provider.inverted_polarity is False:
if alert_level < 3 and models.RequestProviderResult.objects.filter(
request_id=request_id,
provider_id=provider_id,
status=1,
result__lt=provider.alert_below).count() > 0:
alert_level = 3

elif alert_level < 2 and models.RequestProviderResult.objects.filter(
request_id=request_id,
provider_id=provider_id,
status=1,
result__lt=provider.warning_below).count() > 0:
alert_level = 2
else:
if alert_level < 3 and models.RequestProviderResult.objects.filter(
request_id=request_id,
provider_id=provider_id,
status=1,
result__gt=provider.alert_below).count() > 0:
alert_level = 3

elif alert_level < 2 and models.RequestProviderResult.objects.filter(
request_id=request_id,
provider_id=provider_id,
status=1,
result__gt=provider.warning_below).count() > 0:
alert_level = 2

res_values = models.RequestProviderResult.objects.filter(
request_id=request_id,
provider__instrument_id=instrument_id,
status=1
).aggregate(Max('result'), Max('code'))

if res_values['result__max'] is None:
res_values['result__max'] = 0
if res_values['code__max'] is None:
res_values['code__max'] = 2 # Warning

status_values = models.RequestProviderResult.objects.filter(request_id=request_id,
provider__instrument_id=instrument_id
).aggregate(Min('status'), Max('status'))
Expand All @@ -168,7 +215,7 @@ def create_verification_summary(self, request_id, instrument_id):
# Compute average result for providers
result.result = res_values['result__max']
# Set the maximum alert level as the final level
result.code = res_values['code__max']
result.code = max(res_values['code__max'], alert_level)
result.save()

# If there are no missing requests for this learner and instrument in the activity, update the activity report
Expand Down

0 comments on commit 8d0fd3e

Please sign in to comment.