Skip to content

Commit

Permalink
Merge pull request #215 from avantifellows/more-tests
Browse files Browse the repository at this point in the history
More tests
  • Loading branch information
deepansh96 authored Jul 3, 2021
2 parents 723ebb3 + 1c9e118 commit 00288e2
Show file tree
Hide file tree
Showing 4 changed files with 340 additions and 10 deletions.
38 changes: 31 additions & 7 deletions entries/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,40 @@ class Meta:
"updated_at",
]

def validate_plio(self, plio):
"""Ensure that a session is created only for a published plio"""
if plio.status == "draft":
def validate(self, data):
"""
All validation checks happen in this method. Currently these checks are defined
- A session can only be created for a published plio
- `is_first` is set properly depending on if a session already exists or not
"""
# validate plio's status
if data["plio"].status == "draft":
raise serializers.ValidationError(
"A session can only be created for a published plio"
)
return plio

# set `is_first` properly
last_session = (
Session.objects.filter(plio_id=data["plio"].id)
.filter(user_id=data["user"].id)
.first()
)

if self.context["view"].action == "create":
# while creating a session, check if any session already exists
if last_session:
data["is_first"] = False
else:
data["is_first"] = True
elif self.context["view"].action == "update":
# while updating a session, check if the session being updated
# is the very first session
if f"{last_session.id}" == self.context["view"].kwargs["pk"]:
data["is_first"] = True
else:
data["is_first"] = False

return data

def create(self, validated_data):
"""
Expand All @@ -59,9 +86,6 @@ def create(self, validated_data):
if key not in validated_data:
validated_data[key] = last_session_data[key]

else:
validated_data["is_first"] = True

# get the newly created session object
session = Session.objects.create(**validated_data)

Expand Down
156 changes: 153 additions & 3 deletions entries/tests.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,163 @@
import json
from django.urls import reverse
from rest_framework import status

from plio.tests import BaseTestCase
from plio.models import Plio, Video, Item
from entries.models import Session


class SessionTestCase(BaseTestCase):
def setUp(self):
super().setUp()
# seed a video
self.video = Video.objects.create(
title="Video 1",
url="https://www.youtube.com/watch?v=vnISjBbrMUM",
duration=10,
)
# seed some plios
self.plio_1 = Plio.objects.create(
name="Plio 1", video=self.video, created_by=self.user
)

def test_for_session(self):
# write API calls here
self.assertTrue(True)
def test_cannot_create_session_for_draft_plio(self):
response = self.client.post(reverse("sessions-list"), {"plio": self.plio_1.id})
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
json.loads(response.content)["non_field_errors"][0],
"A session can only be created for a published plio",
)

def test_can_create_session_for_published_plio(self):
# set plio_1 as published
self.plio_1.status = "published"
self.plio_1.save()
response = self.client.post(reverse("sessions-list"), {"plio": self.plio_1.id})
self.assertEqual(response.status_code, status.HTTP_201_CREATED)

def test_fresh_session_created_if_no_old_sessions_exist(self):
"""
If no old sessions exist, a fresh session should be
created and should contain all default values
"""
# seed two items linked to plio_1
item_1 = Item.objects.create(type="question", plio=self.plio_1, time=1)
item_2 = Item.objects.create(type="question", plio=self.plio_1, time=2)

# publish plio_1
self.plio_1.status = "published"
self.plio_1.save()

# create a new session for `plio_1` by `user`
response = self.client.post(reverse("sessions-list"), {"plio": self.plio_1.id})
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertTrue(response.data["is_first"])
self.assertEqual(len(response.data["session_answers"]), 2)
self.assertEqual(response.data["session_answers"][0]["item_id"], item_1.id)
self.assertEqual(response.data["session_answers"][1]["item_id"], item_2.id)
self.assertEqual(response.data["retention"], ("0," * self.video.duration)[:-1])

def test_old_session_can_be_updated(self):
"""
An already created session can be updated with details
"""
# publish plio_1
self.plio_1.status = "published"
self.plio_1.save()

# create a new, first session for plio_1
response = self.client.post(reverse("sessions-list"), {"plio": self.plio_1.id})
session_1 = response.data
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertTrue(session_1["is_first"])

# update that session with some details
response = self.client.put(
reverse("sessions-detail", args=[session_1["id"]]),
{
"plio": self.plio_1.id,
"watch_time": 5.00,
"retention": "1,1,1,1,1,0,0,0,0,0",
},
)
session_1_updated = response.data
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertTrue(session_1_updated["is_first"])
self.assertEqual(session_1_updated["id"], session_1["id"])

def test_old_session_details_used_if_old_sessions_exist(self):
"""
If old sessions exist, a new session created should carry
over all the details from the older session
"""
# seed two items linked to plio_1
Item.objects.create(type="question", plio=self.plio_1, time=1)
Item.objects.create(type="question", plio=self.plio_1, time=2)

# publish plio_1
self.plio_1.status = "published"
self.plio_1.save()

# create a new, first session for plio_1
response = self.client.post(reverse("sessions-list"), {"plio": self.plio_1.id})
session_1 = response.data
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertTrue(session_1["is_first"])

# update that session with some details
response = self.client.put(
reverse("sessions-detail", args=[session_1["id"]]),
{
"plio": self.plio_1.id,
"watch_time": 5.00,
"retention": "1,1,1,1,1,0,0,0,0,0",
},
)
session_1_updated = response.data
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertTrue(session_1_updated["is_first"])
self.assertEqual(session_1_updated["id"], session_1["id"])

# creating a new session for this user-plio combination
# details of the last sessions should be passed along to this session
response = self.client.post(reverse("sessions-list"), {"plio": self.plio_1.id})
session_2 = response.data
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertNotEqual(session_2["id"], session_1_updated["id"])
self.assertEqual(len(session_2["session_answers"]), 2)
self.assertEqual(session_2["retention"], session_1_updated["retention"])
self.assertEqual(session_2["watch_time"], session_1_updated["watch_time"])
self.assertFalse(session_2["is_first"])

# mocking the answering of a question
response = self.client.put(
reverse(
"session-answers-detail", args=[session_2["session_answers"][0]["id"]]
),
{
"id": session_2["session_answers"][0]["id"],
"item": session_2["session_answers"][0]["item_id"],
"session": session_2["id"],
"answer": 0,
},
)

# create a new session for the user-plio combination,
# it should have the session_answer details of session_2
response = self.client.post(reverse("sessions-list"), {"plio": self.plio_1.id})
session_3 = response.data
#
session_2_instance = Session.objects.filter(id=int(session_2["id"])).first()
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(
session_3["session_answers"][0]["item_id"],
session_2_instance.sessionanswer_set.values()[0]["item_id"],
)
self.assertEqual(
session_3["session_answers"][0]["answer"],
session_2_instance.sessionanswer_set.values()[0]["answer"],
)


class SessionAnswerTestCase(BaseTestCase):
Expand Down
148 changes: 148 additions & 0 deletions plio/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,154 @@ def test_duplicate(self):
self.assertNotEqual(plio.uuid, response.data["uuid"])
self.assertEqual(plio.name, response.data["name"])

def test_default_ordering_when_no_ordering_specified(self):
# create a third plio
plio_3 = Plio.objects.create(
name="Plio 3", video=self.video, created_by=self.user
)

# make a request to list the plio uuids without specifying any order
# NOTE: default ordering should come out to be '-updated_at'
# order of plios should be [plio_3, plio_2, plio_1]
response = self.client.get("/api/v1/plios/list_uuid/")
self.assertListEqual(
[plio.uuid for plio in Plio.objects.order_by("-updated_at")],
response.data["results"],
)
# also manually checking the order
self.assertListEqual(
[plio_3.uuid, self.plio_2.uuid, self.plio_1.uuid],
response.data["results"],
)

# update the first plio - ordering should change according to 'updated_at'
self.plio_1.name = "updated Plio 1"
self.plio_1.save()

# make a request to list the plio uuids
# NOTE: default ordering should come out to be '-updated_at'
# order of plios should be [plio_1, plio_3, plio_2]
response = self.client.get("/api/v1/plios/list_uuid/")
self.assertListEqual(
[plio.uuid for plio in Plio.objects.order_by("-updated_at")],
response.data["results"],
)
# also manually checking the order
self.assertListEqual(
[self.plio_1.uuid, plio_3.uuid, self.plio_2.uuid],
response.data["results"],
)

def test_ordering_applied_as_specified(self):
# create a third plio
plio_3 = Plio.objects.create(
name="Plio 3", video=self.video, created_by=self.user
)

# ordering by "name"
# update the names
self.plio_1.name = "A_plio"
self.plio_1.save()
self.plio_2.name = "B_plio"
self.plio_2.save()
plio_3.name = "C_plio"
plio_3.save()

# `list_uuid` should give the result ordered as [plio_1, plio_2, plio_3]
# when "name" ordering is specified
response = self.client.get("/api/v1/plios/list_uuid/", {"ordering": "name"})
self.assertListEqual(
[plio.uuid for plio in Plio.objects.order_by("name")],
response.data["results"],
)
# also manually checking the order
self.assertListEqual(
[self.plio_1.uuid, self.plio_2.uuid, plio_3.uuid],
response.data["results"],
)

# ordering by "-name"
# 'list_uuid` should give the result ordered as [plio_3, plio_2, plio_1]
# when "-name" ordering is specified
response = self.client.get("/api/v1/plios/list_uuid/", {"ordering": "-name"})
self.assertListEqual(
[plio.uuid for plio in Plio.objects.order_by("-name")],
response.data["results"],
)
# also manually checking the order
self.assertListEqual(
[plio_3.uuid, self.plio_2.uuid, self.plio_1.uuid],
response.data["results"],
)

# ordering by 'created_at'
# 'list_uuid` should give the result ordered as [plio_1, plio_2, plio_3]
# when "created_at" ordering is specified
response = self.client.get(
"/api/v1/plios/list_uuid/", {"ordering": "created_at"}
)
self.assertListEqual(
[plio.uuid for plio in Plio.objects.order_by("created_at")],
response.data["results"],
)
# also manually checking the order
self.assertListEqual(
[self.plio_1.uuid, self.plio_2.uuid, plio_3.uuid],
response.data["results"],
)

# ordering by "-unique_viewers"
# stimulate some users watching the created plios
user_3 = User.objects.create(mobile="+918877665544")

# seed sessions such that the three plios have this decending
# configuration of number of unique viewers
# plio_3 - 3 | plio_2 - 2 | plio_1 - 1
Session.objects.create(plio=plio_3, user=user_3)
Session.objects.create(plio=plio_3, user=self.user_2)
Session.objects.create(plio=plio_3, user=self.user)

Session.objects.create(plio=self.plio_2, user=self.user_2)
Session.objects.create(plio=self.plio_2, user=self.user)

Session.objects.create(plio=self.plio_1, user=self.user)

# 'list_uuid` should give the result ordered as [plio_3, plio_2, plio_1]
# when "-unique_viewers" ordering is specified
response = self.client.get(
"/api/v1/plios/list_uuid/", {"ordering": "-unique_viewers"}
)
self.assertListEqual(
[plio_3.uuid, self.plio_2.uuid, self.plio_1.uuid], response.data["results"]
)

# ordering by "-unique_viewers" and "name"
# 'list_uuid` should give the result ordered as [plio_3, plio_1, plio_2]
# when ordering is specified as "-unique_viewers" and "name"

# add one more unique_view to plio_1 so that plio_1 and plio_2 both have 2 views each
# that way, the second ordering will be done using the "name"
Session.objects.create(plio=self.plio_1, user=self.user_2)
response = self.client.get(
"/api/v1/plios/list_uuid/", {"ordering": "-unique_viewers,name"}
)
self.assertListEqual(
[plio_3.uuid, self.plio_1.uuid, self.plio_2.uuid], response.data["results"]
)

def test_invalid_ordering_results_in_default_ordering(self):
# create a third plio
Plio.objects.create(name="Plio 3", video=self.video, created_by=self.user)

# order by some invalid ordering string - "xyz"
# `list_uuid` should give the result ordered as [plio_3, plio_2, plio_1]
# because an invalid ordering field will result in the default ordering
response = self.client.get("/api/v1/plios/list_uuid/", {"ordering": "xyz"})
self.assertListEqual(
[plio.uuid for plio in Plio.objects.order_by("-updated_at")],
response.data["results"],
)


class VideoTestCase(BaseTestCase):
def setUp(self):
Expand Down
8 changes: 8 additions & 0 deletions users/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,20 @@ def has_object_permission(self, request, view, obj):
if request.user.is_superuser:
return True

# allow anyone to retrieve the instance
if view.action == "retrieve":
return True

if view.action == "destroy":
# When deleting an organization-user, we will only send the primary key.
# So to determine if logged-in user is authorized to perform action,
# we need to pick org id from object
organization_id = obj.organization_id
else:
# When updating an organization user, we will also send a new org id.
# So to determine if logged-in user is authorized to perform action,
# we need to pick org id from the request (which is the updated
# org id for that organization-user)
organization_id = request.data["organization"]

user_organization_role = request.user.get_role_for_organization(organization_id)
Expand Down

0 comments on commit 00288e2

Please sign in to comment.