Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jlc/certificates metrics #96

Merged
merged 1 commit into from
Sep 13, 2023
Merged

Jlc/certificates metrics #96

merged 1 commit into from
Sep 13, 2023

Conversation

johanseto
Copy link
Collaborator

Description

Add certificates key for the metric backend.
This add a certificates key for each course metric with this shape for course endpoint

{
            "certificates": {
                "verified": {"downloadable": 0, "notpassing": 0},
                "honor": {"downloadable": 0, "notpassing": 0},
                "audit": {"downloadable": 0, "notpassing": 0},
                "professional": {"downloadable": 0, "notpassing": 0},
                "no-id-professional": {"downloadable": 5, "notpassing": 4},
                "masters": {"downloadable": 0, "notpassing": 0},
                "executive-education": {"downloadable": 0, "notpassing": 0},
                "paid-executive-education": {"downloadable": 0, "notpassing": 0},
                "paid-bootcamp": {"downloadable": 0, "notpassing": 0},
                "total": 9,
            }
}

For the tenant endpoint only the total certificates of the tenant is shown:

{
    "learners": 1,
    "courses": 3,
    "instructors": 2,
    "components": {
        "discussion": 0,
        "drag-and-drop-v2": 0,
        "html": 133,
        "openassessment": 0,
        "problem": 49,
        "video": 0
    },
    "certiticates": 12
}

Testing instructions

Clone this branch and check the behavior of the stats endpoints.

/eox-nelp/api/stats/v1/tenant/
/eox-nelp/api/stats/v1/courses/
/eox-nelp/api/stats/v1/courses/course-v1:edX+cd202+2023

After

Peek 2023-09-12 14-18

Additional information

Jira story:
https://edunext.atlassian.net/browse/FUTUREX-489

Checklist for Merge

  • Tested in a remote environment
  • Updated documentation
  • Rebased master/main
  • Squashed commits

"executive-education": {...}
"paid-executive-education":{...},
"paid-bootcamp": {...},
"total": 0
Copy link
Collaborator

@andrey-canon andrey-canon Sep 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since you are splitting the certificates based on their status the total metric should reflect also that division

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain this one a little more, I mean I am setting the total without the division.
So the division would reflect something like the total:

"total" : {
"no-id-professional": 5,
"audit": 5
}

Is that what you say?
Because if is that I prefer to set the total of each one inside each key?? But I didn't find it necessary due you only have to sum the field of each one

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't say mode

                "total": {
                    "downloadable": 5,
                    "notpassing": 4,
                },

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't say mode

                "total": {
                    "downloadable": 5,
                    "notpassing": 4,
                },

@andrey-canon what about this approach ?
Peek 2023-09-12 17-55

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you remove the modes ?

@@ -95,6 +95,26 @@ class Migration(migrations.Migration):
('org', models.CharField(blank=True, max_length=500, null=True))
],
),
migrations.CreateModel(
Copy link
Collaborator

@andrey-canon andrey-canon Sep 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are you creating a a backend if you are creating the model ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the backend allows me to load the class that passes the data to the test db.

GeneratedCertificate.objects.get_or_create(**{

def get_generated_certificate():
"""Return test model.
Returns:
Generated Certificates dummy model.
"""
generated_certificate_fields = {
"user": models.ForeignKey(User, on_delete=models.CASCADE),
"course_id": CourseKeyField(max_length=255, blank=True, default=None),
"verify_uuid": models.CharField(max_length=32, blank=True, default='', db_index=True),
"grade": models.CharField(max_length=5, blank=True, default=''),
"key": models.CharField(max_length=32, blank=True, default=''),
"distinction": models.BooleanField(default=False),
"status": models.CharField(max_length=32, default='unavailable'),
"mode": models.CharField(max_length=32, choices=MODES, default=MODES.honor),
"name": models.CharField(blank=True, max_length=255),
"created_date": models.DateTimeField(auto_now_add=True),
"modified_date": models.DateTimeField(auto_now=True),
"download_uuid": models.CharField(max_length=32, blank=True, default=''),
"download_url": models.CharField(max_length=128, blank=True, default=''),
"error_reason": models.CharField(max_length=512, blank=True, default=''),
# not model fields :
"MODES": MODES,
}
return create_test_model(
"GeneratedCertificate", "eox_nelp", __package__, generated_certificate_fields
)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generally we don't duplicate models from edx-platform, why this case is so especial ?

Copy link
Collaborator Author

@johanseto johanseto Sep 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually is because in the test I use the model to generate the certificates in test db. So the mainly reason is that, as you can see there course_overview also was recreated, but with less fields

migrations.CreateModel(
name='CourseOverview',
fields=[
(
'id',
opaque_keys.edx.django.models.CourseKeyField(
db_index=True,
primary_key=True,
max_length=255,
verbose_name='ID',
),
),
('org', models.CharField(blank=True, max_length=500, null=True))
],
),

The reasons is that I want to test against like "real certs data"...

Copy link
Collaborator Author

@johanseto johanseto Sep 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So in the test, as you can see I don't mock any function of the certificates because the django test db has the model and data(GeneratedCertficates). So functions like GeneratedCertficates.objects... work and return data from test db.

GeneratedCertificate.objects.get_or_create(**{
'user': user,
'course_id': CourseKey.from_string("course-v1:test+Cx105+2022_T4"),
'verify_uuid': 'ddad6d87c5084a3facfd7925b0b2b9a3',
'download_uuid': '',
'download_url': '',
'grade': '71.0',
'key': '807e31d92ab6aeaab514d7669bb2b014',
'distinction': False,
'status': 'downloadable',
'mode': 'no-id-professional',
'name': 'Peter Park',
'error_reason': '',
})
GeneratedCertificate.objects.get_or_create(**{
'user': user2,
'course_id': CourseKey.from_string("course-v1:test+Cx105+2022_T4"),
'verify_uuid': 'ddad6d87c5084a3facfd7925b0b2b9a3',
'download_uuid': '',
'download_url': '',
'grade': '59.0',
'key': '807e31d92ab6aeaab514d7669bb2b014',
'distinction': False,
'status': 'notpassing',

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Course overview was created because another model use that as foreign key, there was no another option

IMO there are another alternatives like Mock that could fit here without adding fields that you even don't use

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I started trying to use the mock approach, therefore as I used different Django queryset attributes and mixed them, I found that I have to do a lot of different mocks approaches and also with sense. So I stated to be a little mixed, so finally, I preferred to load the model and get data as the django queryset would work.

# this block set the CourseEnrollment mock and its returned values.
filter_result = CourseEnrollment.objects.filter.return_value
values_result = filter_result.values.return_value
distinct_result = values_result.distinct.return_value
distinct_result.count.return_value = self.expected_returned_enrollments
# this block set the CourseAccessRole mock and its returned values.
filter_result = CourseAccessRole.objects.filter.return_value
values_result = filter_result.values.return_value
distinct_result = values_result.distinct.return_value
distinct_result.count.return_value = self.expected_returned_roles
# this block set the GeneratedCertificates mock and its returned values.

Also I set another fields, maybe extra but that could be useful if others created a certificate in the django db test model.

Actually all was loaded from here. Practically I have the same model that the openedx
https://github.com/openedx/edx-platform/blob/master/lms/djangoapps/certificates/models.py#L224-L240

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the point we can not copy all the models that openedx use

style: isort and pylint pass

chore: set tests checkpoint with cert backend

style: pylint and isort

chore: rename correct cert_status

chore: add new dosctrings

feat: add test for course certificates metric fx

test: add test for view including total certs

chore: rename `not_passing`

refactor: pr recommendations for total count

refactor: use GeneratedCertificates main fields

PR recomendations:
This ensure I create a django test model that only use the fields
that test or the implementation use.\
@johanseto johanseto merged commit f19260e into master Sep 13, 2023
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size/m m lines label test
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants