Files
edx-platform/lms/djangoapps/foldit/tests.py
Julian Arni 6e92666a20 Fixed score order.
Less is more.
2013-03-11 14:57:19 -04:00

339 lines
12 KiB
Python

import json
import logging
from functools import partial
from django.contrib.auth.models import User
from django.test import TestCase
from django.test.client import RequestFactory
from django.conf import settings
from django.core.urlresolvers import reverse
from foldit.views import foldit_ops, verify_code
from foldit.models import PuzzleComplete, Score
from student.models import UserProfile, unique_id_for_user
from datetime import datetime, timedelta
log = logging.getLogger(__name__)
class FolditTestCase(TestCase):
def setUp(self):
self.factory = RequestFactory()
self.url = reverse('foldit_ops')
pwd = 'abc'
self.user = User.objects.create_user('testuser', 'test@test.com', pwd)
self.user2 = User.objects.create_user('testuser2', 'test2@test.com', pwd)
self.unique_user_id = unique_id_for_user(self.user)
self.unique_user_id2 = unique_id_for_user(self.user2)
now = datetime.now()
self.tomorrow = now + timedelta(days=1)
self.yesterday = now - timedelta(days=1)
UserProfile.objects.create(user=self.user)
UserProfile.objects.create(user=self.user2)
def make_request(self, post_data, user=None):
request = self.factory.post(self.url, post_data)
request.user = self.user if not user else user
return request
def make_puzzle_score_request(self, puzzle_ids, best_scores, user=None):
"""
Given lists of puzzle_ids and best_scores (must have same length), make a
SetPlayerPuzzleScores request and return the response.
"""
if not(type(best_scores) == list):
best_scores = [best_scores]
if not(type(puzzle_ids) == list):
puzzle_ids = [puzzle_ids]
user = self.user if not user else user
def score_dict(puzzle_id, best_score):
return {"PuzzleID": puzzle_id,
"ScoreType": "score",
"BestScore": best_score,
# current scores don't actually matter
"CurrentScore": best_score + 0.01,
"ScoreVersion": 23}
scores = [score_dict(pid, bs) for pid, bs in zip(puzzle_ids, best_scores)]
scores_str = json.dumps(scores)
verify = {"Verify": verify_code(user.email, scores_str),
"VerifyMethod": "FoldItVerify"}
data = {'SetPlayerPuzzleScoresVerify': json.dumps(verify),
'SetPlayerPuzzleScores': scores_str}
request = self.make_request(data, user)
response = foldit_ops(request)
self.assertEqual(response.status_code, 200)
return response
def test_SetPlayerPuzzleScores(self):
puzzle_id = 994391
best_score = 0.078034
response = self.make_puzzle_score_request(puzzle_id, [best_score])
self.assertEqual(response.content, json.dumps(
[{"OperationID": "SetPlayerPuzzleScores",
"Value": [{
"PuzzleID": puzzle_id,
"Status": "Success"}]}]))
# There should now be a score in the db.
top_10 = Score.get_tops_n(10, puzzle_id)
self.assertEqual(len(top_10), 1)
self.assertEqual(top_10[0]['score'], Score.display_score(best_score))
def test_SetPlayerPuzzleScores_many(self):
response = self.make_puzzle_score_request([1, 2], [0.078034, 0.080000])
self.assertEqual(response.content, json.dumps(
[{"OperationID": "SetPlayerPuzzleScores",
"Value": [{
"PuzzleID": 1,
"Status": "Success"},
{"PuzzleID": 2,
"Status": "Success"}]}]))
def test_SetPlayerPuzzleScores_multiple(self):
"""
Check that multiple posts with the same id are handled properly
(keep latest for each user, have multiple users work properly)
"""
orig_score = 0.07
puzzle_id = '1'
response = self.make_puzzle_score_request([puzzle_id], [orig_score])
# There should now be a score in the db.
top_10 = Score.get_tops_n(10, puzzle_id)
self.assertEqual(len(top_10), 1)
self.assertEqual(top_10[0]['score'], Score.display_score(orig_score))
# Reporting a better score should overwrite
better_score = 0.06
response = self.make_puzzle_score_request([1], [better_score])
top_10 = Score.get_tops_n(10, puzzle_id)
self.assertEqual(len(top_10), 1)
# Floats always get in the way, so do almostequal
self.assertAlmostEqual(top_10[0]['score'],
Score.display_score(better_score),
delta=0.5)
# reporting a worse score shouldn't
worse_score = 0.065
response = self.make_puzzle_score_request([1], [worse_score])
top_10 = Score.get_tops_n(10, puzzle_id)
self.assertEqual(len(top_10), 1)
# should still be the better score
self.assertAlmostEqual(top_10[0]['score'],
Score.display_score(better_score),
delta=0.5)
def test_SetPlayerPuzzleScores_manyplayers(self):
"""
Check that when we send scores from multiple users, the correct order
of scores is displayed. Note that, before being processed by
display_score, lower scores are better.
"""
puzzle_id = ['1']
player1_score = 0.08
player2_score = 0.02
response1 = self.make_puzzle_score_request(puzzle_id, player1_score,
self.user)
# There should now be a score in the db.
top_10 = Score.get_tops_n(10, puzzle_id)
self.assertEqual(len(top_10), 1)
self.assertEqual(top_10[0]['score'], Score.display_score(player1_score))
response2 = self.make_puzzle_score_request(puzzle_id, player2_score,
self.user2)
# There should now be two scores in the db
top_10 = Score.get_tops_n(10, puzzle_id)
self.assertEqual(len(top_10), 2)
# Top score should be player2_score. Second should be player1_score
self.assertAlmostEqual(top_10[0]['score'],
Score.display_score(player2_score),
delta=0.5)
self.assertAlmostEqual(top_10[1]['score'],
Score.display_score(player1_score),
delta=0.5)
# Top score user should be self.user2.username
self.assertEqual(top_10[0]['username'], self.user2.username)
def test_SetPlayerPuzzleScores_error(self):
scores = [{"PuzzleID": 994391,
"ScoreType": "score",
"BestScore": 0.078034,
"CurrentScore": 0.080035,
"ScoreVersion": 23}]
validation_str = json.dumps(scores)
verify = {"Verify": verify_code(self.user.email, validation_str),
"VerifyMethod": "FoldItVerify"}
# change the real string -- should get an error
scores[0]['ScoreVersion'] = 22
scores_str = json.dumps(scores)
data = {'SetPlayerPuzzleScoresVerify': json.dumps(verify),
'SetPlayerPuzzleScores': scores_str}
request = self.make_request(data)
response = foldit_ops(request)
self.assertEqual(response.status_code, 200)
response_data = json.loads(response.content)
self.assertEqual(response.content,
json.dumps([{
"OperationID": "SetPlayerPuzzleScores",
"Success": "false",
"ErrorString": "Verification failed",
"ErrorCode": "VerifyFailed"}]))
def make_puzzles_complete_request(self, puzzles):
"""
Make a puzzles complete request, given an array of
puzzles. E.g.
[ {"PuzzleID": 13, "Set": 1, "SubSet": 2},
{"PuzzleID": 53524, "Set": 1, "SubSet": 1} ]
"""
puzzles_str = json.dumps(puzzles)
verify = {"Verify": verify_code(self.user.email, puzzles_str),
"VerifyMethod":"FoldItVerify"}
data = {'SetPuzzlesCompleteVerify': json.dumps(verify),
'SetPuzzlesComplete': puzzles_str}
request = self.make_request(data)
response = foldit_ops(request)
self.assertEqual(response.status_code, 200)
return response
@staticmethod
def set_puzzle_complete_response(values):
return json.dumps([{"OperationID":"SetPuzzlesComplete",
"Value": values}])
def test_SetPlayerPuzzlesComplete(self):
puzzles = [ {"PuzzleID": 13, "Set": 1, "SubSet": 2},
{"PuzzleID": 53524, "Set": 1, "SubSet": 1} ]
response = self.make_puzzles_complete_request(puzzles)
self.assertEqual(response.content,
self.set_puzzle_complete_response([13, 53524]))
def test_SetPlayerPuzzlesComplete_multiple(self):
"""Check that state is stored properly"""
puzzles = [ {"PuzzleID": 13, "Set": 1, "SubSet": 2},
{"PuzzleID": 53524, "Set": 1, "SubSet": 1} ]
response = self.make_puzzles_complete_request(puzzles)
self.assertEqual(response.content,
self.set_puzzle_complete_response([13, 53524]))
puzzles = [ {"PuzzleID": 14, "Set": 1, "SubSet": 3},
{"PuzzleID": 15, "Set": 1, "SubSet": 1} ]
response = self.make_puzzles_complete_request(puzzles)
self.assertEqual(response.content,
self.set_puzzle_complete_response([13, 14, 15, 53524]))
def test_SetPlayerPuzzlesComplete_level_complete(self):
"""Check that the level complete function works"""
puzzles = [ {"PuzzleID": 13, "Set": 1, "SubSet": 2},
{"PuzzleID": 53524, "Set": 1, "SubSet": 1} ]
response = self.make_puzzles_complete_request(puzzles)
self.assertEqual(response.content,
self.set_puzzle_complete_response([13, 53524]))
puzzles = [ {"PuzzleID": 14, "Set": 1, "SubSet": 3},
{"PuzzleID": 15, "Set": 1, "SubSet": 1} ]
response = self.make_puzzles_complete_request(puzzles)
self.assertEqual(response.content,
self.set_puzzle_complete_response([13, 14, 15, 53524]))
is_complete = partial(
PuzzleComplete.is_level_complete, self.unique_user_id)
self.assertTrue(is_complete(1, 1))
self.assertTrue(is_complete(1, 3))
self.assertTrue(is_complete(1, 2))
self.assertFalse(is_complete(4, 5))
puzzles = [ {"PuzzleID": 74, "Set": 4, "SubSet": 5} ]
response = self.make_puzzles_complete_request(puzzles)
self.assertTrue(is_complete(4, 5))
# Now check due dates
self.assertTrue(is_complete(1, 1, due=self.tomorrow))
self.assertFalse(is_complete(1, 1, due=self.yesterday))
def test_SetPlayerPuzzlesComplete_error(self):
puzzles = [ {"PuzzleID": 13, "Set": 1, "SubSet": 2},
{"PuzzleID": 53524, "Set": 1, "SubSet": 1} ]
puzzles_str = json.dumps(puzzles)
verify = {"Verify": verify_code(self.user.email, puzzles_str + "x"),
"VerifyMethod":"FoldItVerify"}
data = {'SetPuzzlesCompleteVerify': json.dumps(verify),
'SetPuzzlesComplete': puzzles_str}
request = self.make_request(data)
response = foldit_ops(request)
self.assertEqual(response.status_code, 200)
response_data = json.loads(response.content)
self.assertEqual(response.content,
json.dumps([{
"OperationID": "SetPuzzlesComplete",
"Success": "false",
"ErrorString": "Verification failed",
"ErrorCode": "VerifyFailed"}]))