def test_new_solution_override_old_solutions( self, exercise: Exercise, student_user: User, ): first_solution = conftest.create_solution(exercise, student_user) second_solution = conftest.create_solution(exercise, student_user) assert second_solution.state == self.created_state assert first_solution.refresh().state == self.old_solution_state next_unchecked = Solution.next_unchecked() assert next_unchecked is not None assert next_unchecked.id == second_solution.id next_unchecked = Solution.next_unchecked_of(exercise.id) assert next_unchecked is not None assert next_unchecked.id == second_solution.id assert next_unchecked.start_checking() assert next_unchecked.refresh().state == self.in_checking_state assert Solution.next_unchecked() is None assert Solution.next_unchecked_of(exercise.id) is None general_tasks.reset_solution_state_if_needed(second_solution.id) next_unchecked = Solution.next_unchecked() next_unchecked_by_id = Solution.next_unchecked_of(exercise.id) assert next_unchecked is not None and next_unchecked_by_id is not None assert next_unchecked.id == second_solution.id assert next_unchecked_by_id.id == second_solution.id
def test_new_solution_override_old_solutions( self, exercise: Exercise, student_user: User, ): first_solution = conftest.create_solution(exercise, student_user) second_solution = conftest.create_solution(exercise, student_user) assert second_solution.state == self.created_state assert first_solution.refresh().state == self.old_solution_state next_unchecked = Solution.next_unchecked() assert next_unchecked is not None assert next_unchecked.id == second_solution.id next_unchecked = Solution.next_unchecked_of(exercise.id) assert next_unchecked is not None assert next_unchecked.id == second_solution.id assert next_unchecked.start_checking() assert next_unchecked.refresh().state == self.in_checking_state assert Solution.next_unchecked() is None assert Solution.next_unchecked_of(exercise.id) is None general_tasks.reset_solution_state_if_needed(second_solution.id) next_unchecked = Solution.next_unchecked() next_unchecked_by_id = Solution.next_unchecked_of(exercise.id) assert next_unchecked is not None and next_unchecked_by_id is not None assert next_unchecked.id == second_solution.id assert next_unchecked_by_id.id == second_solution.id third_solution = conftest.create_solution( exercise, student_user, code='123', ) fourth_solution = conftest.create_solution( exercise, student_user, code='1234', ) assert not Solution.is_duplicate( third_solution.hashed, student_user, exercise, already_hashed=True, ) assert Solution.is_duplicate( fourth_solution.hashed, student_user, exercise, already_hashed=True, )
def test_strange_solution_with_no_files( exercise: Exercise, student_user: User, staff_user: User, ): solution = conftest.create_solution( exercise, student_user, files=[], hash_='koko', ) staff_client = conftest.get_logged_user(staff_user.username) view_response = staff_client.get(f'{routes.SOLUTIONS}/{solution.id}') assert view_response.status_code == 200 solution = Solution.get_by_id(solution.id) assert solution.state == Solution.STATES.DONE.name to_show_in_view = { 'solution': solution, 'file_id': None, 'shared_url': '', 'is_manager': False, 'solution_files': (), 'viewer_is_solver': True, } with pytest.raises(ResourceNotFound): assert get_view_parameters(**to_show_in_view) user_client = conftest.get_logged_user(student_user.username) assert len(list(notifications.get(student_user))) == 1 view_response = user_client.get(f'{routes.SOLUTIONS}/{solution.id}') assert view_response.status_code == 404
def test_share_solution_by_another_user( exercise: Exercise, student_user: User, ): student_user2 = conftest.create_student_user(index=1) solution = conftest.create_solution(exercise, student_user2) client = conftest.get_logged_user(student_user.username) not_exist_share_response = client.post('/share', data=json.dumps({ 'solutionId': solution.id + 1, 'act': 'get', }), content_type='application/json') assert not_exist_share_response.status_code == 404 not_user_solution_share_response = client.post( '/share', data=json.dumps({ 'solutionId': solution.id, 'act': 'get', }), content_type='application/json', ) assert not_user_solution_share_response.status_code == 403
def test_mark_as_checked( exercise: Exercise, student_user: User, staff_user: User, solution: Solution, ): # Basic functionality assert solution.state == Solution.STATES.CREATED.name marked = solutions.mark_as_checked(solution.id, staff_user.id) # HELL WITH PEEWEE!!! solution = Solution.get_by_id(solution.id) assert marked assert solution.state == Solution.STATES.DONE.name assert solution.checker == staff_user # Not duplicating things staff_user2 = conftest.create_staff_user(index=1) solution2 = conftest.create_solution(exercise, student_user) marked = solutions.mark_as_checked(solution2.id, staff_user2.id) solution2 = Solution.get_by_id(solution2.id) assert solution2.state == Solution.STATES.DONE.name assert solution2.checker == staff_user2 # Creates notifications assert len(list(notifications.get(student_user))) == 2
def test_solutions_of_user( staff_user: User, student_user: User, course: Course, solution: Solution, _assessments, ): conftest.create_usercourse(student_user, course) client = conftest.get_logged_user(staff_user.username) client.post( f'/assessment/{solution.id}', data=json.dumps({'assessment': 2}), content_type='application/json', ) solution = Solution.get_by_id(solution.id) assert solution.assessment.name == 'Nice' client.post( f'/assessment/{solution.id}', data=json.dumps({'assessment': None}), content_type='application/json', ) exercise2 = conftest.create_exercise(course, 2) solution2 = conftest.create_solution(exercise2, student_user) client.post( f'/assessment/{solution2.id}', data=json.dumps({'assessment': 3}), content_type='application/json', ) solution2 = Solution.get_by_id(solution2.id) exercises = solution.of_user(student_user.id, from_all_courses=True) assert exercises[0].get('assessment') is None assert exercises[1].get('assessment') == 'Try again'
def test_download_solution( self, exercise: Exercise, student_user: User, ): storage = self.create_zipfile_storage() hash_ = hashing.by_file(storage) solution = conftest.create_solution( exercise=exercise, student_user=student_user, files=list(TestDownloadSolution.get_zip_files()), hash_=hash_, ) client = conftest.get_logged_user(student_user.username) download_response = client.get(f'{routes.DOWNLOADS}/{solution.id}') downloaded_bytes_file = BytesIO(download_response.data) downloaded_zipfile = ZipFile(downloaded_bytes_file, 'r') exist_zipfile = ZipFile(self.zipfile_file, 'r') for exist_filename, downloaded_filename in zip( exist_zipfile.namelist(), downloaded_zipfile.namelist(), ): assert exist_filename == downloaded_filename with exist_zipfile.open(exist_filename, 'r') as exist_file: with downloaded_zipfile.open( downloaded_filename, 'r', ) as downloaded_file: assert exist_file.read() == downloaded_file.read()
def test_view_page( exercise: Exercise, student_user: User, ): student_user2 = conftest.create_student_user(index=1) solution = conftest.create_solution(exercise, student_user) solution2 = conftest.create_solution(exercise, student_user2) client = conftest.get_logged_user(student_user.username) view_response = client.get(f'/view/{solution.id}') assert view_response.status_code == 200 another_user_solution_response = client.get(f'/view/{solution2.id}') assert another_user_solution_response.status_code == 403 not_exist_solution_response = client.get('/view/0') assert not_exist_solution_response.status_code == 404
def test_start_checking(exercise: Exercise, student_user: User): student_user2 = conftest.create_student_user(index=1) exercise2 = conftest.create_exercise(1) solution1 = conftest.create_solution(exercise, student_user) solution2 = conftest.create_solution(exercise2, student_user) solution3 = conftest.create_solution(exercise, student_user2) is_checking = solutions.start_checking(solution=None) assert not is_checking with no_celery: for solution in (solution1, solution2, solution3): assert solution.state == Solution.STATES.CREATED.name is_checking = solutions.start_checking(solution=solution) assert is_checking the_solution = Solution.get_by_id(solution.id) assert the_solution.state == Solution.STATES.IN_CHECKING.name
def test_get_next_unchecked( course: Course, student_user: User, exercise: Exercise, staff_user: User, _assessments, ): student_user2 = conftest.create_student_user(index=1) exercise2 = conftest.create_exercise(course, 2, index=3) solution1 = conftest.create_solution(exercise, student_user) solution2 = conftest.create_solution(exercise2, student_user) solution3 = conftest.create_solution(exercise, student_user2) assert len(list(Solution.select())) == 3 unchecked = solutions.get_next_unchecked(exercise.id) assert unchecked is not None assert unchecked.exercise.id == solution1.exercise.id assert unchecked == solution1 solutions.mark_as_checked(solution1.id, staff_user) unchecked = solutions.get_next_unchecked(exercise.id) assert unchecked is not None assert unchecked.exercise.id == solution3.exercise.id assert unchecked == solution3 solutions.mark_as_checked(solution3.id, staff_user) unchecked = solutions.get_next_unchecked(exercise.id) assert unchecked is None unchecked = solutions.get_next_unchecked() assert unchecked is not None assert unchecked == solution2 solutions.mark_as_checked(solution2.id, staff_user) unchecked = solutions.get_next_unchecked() assert unchecked is None unchecked = solutions.get_next_unchecked(solution2.id) assert unchecked is None
def _duplicate_solution_from_comment( comment: models.Comment, first_solution_code: str, second_solution_code: str, ) -> typing.Tuple[models.Solution, models.Solution]: first_solution: models.Solution = comment.file.solution first_solution.set_state(models.Solution.STATES.DONE) first_solution = first_solution.refresh() solution_file = first_solution.solution_files.get() solution_file.code = first_solution_code solution_file.save() student_user: models.User = conftest.create_student_user(index=1) second_solution = conftest.create_solution( exercise=first_solution.exercise, student_user=student_user, code=second_solution_code, ) return first_solution, second_solution
def test_next_exercise_with_cleanest_code( comment: Comment, staff_user: User, ): student_user: User = conftest.create_student_user(index=1) first_solution = comment.solution comment_text = comment.comment second_solution = conftest.create_solution(comment.solution.exercise, student_user) # comment exists on first solution - second one should be the first next_unchecked = Solution.next_unchecked() assert next_unchecked is not None assert next_unchecked.id == second_solution.id # delete the comment should give us back the first solution Comment.delete_by_id(comment.id) next_unchecked = Solution.next_unchecked() assert next_unchecked is not None assert next_unchecked.id == first_solution.id # if second_solution has comments we should get first solution Comment.create_comment( commenter=staff_user, line_number=1, comment_text=comment_text, file=second_solution.solution_files.get(), is_auto=False, ) next_unchecked = Solution.next_unchecked() assert next_unchecked is not None assert next_unchecked.id == first_solution.id # both have comments - the first one should be the first solution Comment.create_comment( commenter=staff_user, line_number=1, comment_text=comment_text, file=first_solution.solution_files.get(), is_auto=False, ) next_unchecked = Solution.next_unchecked() assert next_unchecked is not None assert next_unchecked.id == first_solution.id
def test_read_related( self, student_user: User, solution: Solution, exercise: Exercise, ): solution2 = conftest.create_solution(student_user, exercise) student_user2 = conftest.create_user(index=1) messages = [ conftest.create_notification(student_user, solution), conftest.create_notification(student_user, solution), conftest.create_notification(student_user, solution), conftest.create_notification(student_user, solution2), conftest.create_notification(student_user2, solution), ] assert all(not n.viewed for n in messages) notifications.read_related(solution.id, student_user) # peewee... messages = [Notification.get_by_id(n.id) for n in messages] assert all(n.viewed for n in messages[:3]) assert all(not n.viewed for n in messages[3:])
def test_share_solution_function( exercise: Exercise, student_user: User, ): student_user2 = conftest.create_student_user(index=1) solution = conftest.create_solution(exercise, student_user2) client2 = conftest.get_logged_user(student_user2.username) # Sharing his own solution shared_response = client2.post('/share', data=json.dumps({ 'solutionId': solution.id, 'act': 'get', }), content_type='application/json') assert shared_response.status_code == 200 # Unknown act of share unknown_shared_response = client2.post('/share', data=json.dumps({ 'solutionId': solution.id, 'act': 'unknown', }), content_type='application/json') assert unknown_shared_response.status_code == 400 # Entering another student solution shared_url = SharedSolution.get_or_none( SharedSolution.solution == solution, ) assert len(shared_url.entries) == 0 conftest.logout_user(client2) client = conftest.get_logged_user(student_user.username) shared_response = client.get(f'{routes.SHARED}/{shared_url}') assert shared_response.status_code == 200 assert len(shared_url.entries) == 1 # Downloading another student solution by solution.id solution_id_download_response = client.get( f'{routes.DOWNLOADS}/{solution.id}', ) assert solution_id_download_response.status_code == 403 # Downloading another student solution download_response = client.get(f'{routes.DOWNLOADS}/{shared_url}', ) assert download_response.status_code == 200 # Deleting another user's solution delete_not_user_solution_response = client.post( '/share', data=json.dumps({ 'solutionId': solution.id, 'act': 'delete', }), content_type='application/json', ) assert delete_not_user_solution_response.status_code == 403 # Deleting his own solution conftest.logout_user(client) client2 = conftest.get_logged_user(student_user2.username) delete_share_response = client2.post('/share', data=json.dumps({ 'solutionId': solution.id, 'act': 'delete', }), content_type='application/json') assert delete_share_response.status_code == 200 # Entering not shared solution after deletion conftest.logout_user(client2) client = conftest.get_logged_user(student_user.username) not_shared_solution_response = client.get( f'{routes.SHARED}/{shared_url}', ) assert not_shared_solution_response.status_code == 404
def test_staff_and_user_comments( exercise: Exercise, student_user: User, staff_user: User, ): solution = conftest.create_solution(exercise, student_user) client = conftest.get_logged_user(staff_user.username) # Enabling user comments option conftest.enable_users_comments() # Creating a comment comment_response = client.post('/comments', data=json.dumps({ 'fileId': solution.files[0].id, 'act': 'create', 'kind': 'text', 'comment': 'try again', 'line': 1, }), content_type='application/json') assert comment_response.status_code == 200 # Creating another comment another_comment_response = client.post( '/comments', data=json.dumps({ 'fileId': solution.files[0].id, 'act': 'create', 'kind': 'text', 'comment': 'hey', 'line': 1, }), content_type='application/json', ) assert another_comment_response.status_code == 200 # Unknown act comment unknown_comment_response = client.post( '/comments', data=json.dumps({ 'fileId': solution.files[0].id, 'act': 'unknown', 'kind': 'text', 'comment': 'hey', 'line': 1, }), content_type='application/json', ) assert unknown_comment_response.status_code == 400 # Not existing fileId comment file_id_comment_response = client.post( '/comments', data=json.dumps({ 'fileId': 99, 'act': 'create', 'kind': 'text', 'comment': 'hey', 'line': 1, }), content_type='application/json', ) assert file_id_comment_response.status_code == 404 # Removing the second comment json_response_another_comment = json.loads( another_comment_response.get_data(as_text=True), ) delete_response = client.get('/comments', query_string={ 'fileId': solution.files[0].id, 'act': 'delete', 'commentId': json_response_another_comment['id'], }, content_type='application/json') assert delete_response.status_code == 200 conftest.logout_user(client) client2 = conftest.get_logged_user(student_user.username) # Trying to remove a comment json_response_comment = json.loads( comment_response.get_data(as_text=True), ) delete_response = client2.get('/comments', query_string={ 'fileId': solution.files[0].id, 'act': 'delete', 'commentId': json_response_comment['id'], }, content_type='application/json') assert delete_response.status_code == 403
def test_user_comments( exercise: Exercise, student_user: User, ): solution = conftest.create_solution(exercise, student_user) client = conftest.get_logged_user(student_user.username) # Creating a comment comment_response = client.post('/comments', data=json.dumps({ 'fileId': solution.files[0].id, 'act': 'create', 'kind': 'text', 'comment': 'hey', 'line': 1, }), content_type='application/json') assert comment_response.status_code == 200 # Creating another comment another_comment_response = client.post( '/comments', data=json.dumps({ 'fileId': solution.files[0].id, 'act': 'create', 'kind': 'text', 'comment': 'noice', 'line': 2, }), content_type='application/json', ) assert another_comment_response.status_code == 200 # Removing the second comment json_response_another_comment = json.loads( another_comment_response.get_data(as_text=True), ) delete_response = client.get('/comments', query_string={ 'fileId': solution.files[0].id, 'act': 'delete', 'commentId': json_response_another_comment['id'], }, content_type='application/json') assert delete_response.status_code == 200 # Disabling users comments option conftest.disable_users_comments() # Trying to remove a comment json_response_comment = json.loads( comment_response.get_data(as_text=True), ) delete_response = client.get('/comments', query_string={ 'fileId': solution.files[0].id, 'act': 'delete', 'commentId': json_response_comment['id'], }, content_type='application/json') assert delete_response.status_code == 403 # Trying to create a comment disable_comment_response = client.post( '/comments', data=json.dumps({ 'fileId': solution.files[0].id, 'act': 'create', 'kind': 'text', 'comment': 'well well well', 'line': 2, }), content_type='application/json', ) assert disable_comment_response.status_code == 403