Ejemplo n.º 1
0
 def request(self, **request):
     request = WSGIRequest(self._base_environ(**request))
     request.user = AnonymousUser()
     return request
Ejemplo n.º 2
0
 def request(self, **request):
     "Construct a generic request object."
     return WSGIRequest(self._base_environ(**request))
Ejemplo n.º 3
0
 def __call__(self, environ, start_response):
     """ Hijack the main loop from the original thread and listen on events on Redis and Websockets"""
     websocket = None
     subscriber = self.Subscriber(self._redis_connection)
     try:
         self.assure_protocol_requirements(environ)
         request = WSGIRequest(environ)
         self.process_request(request)
         channels, echo_message = self.process_subscriptions(request)
         if callable(private_settings.WS4REDIS_ALLOWED_CHANNELS):
             channels = list(
                 private_settings.WS4REDIS_ALLOWED_CHANNELS(
                     request, channels))
         websocket = self.upgrade_websocket(environ, start_response)
         logger.debug('Subscribed to channels: {0}'.format(
             ', '.join(channels)))
         subscriber.set_pubsub_channels(request, channels)
         websocket_fd = websocket.get_file_descriptor()
         listening_fds = [websocket_fd]
         redis_fd = subscriber.get_file_descriptor()
         if redis_fd:
             listening_fds.append(redis_fd)
         subscriber.send_persited_messages(websocket)
         recvmsg = None
         while websocket and not websocket.closed:
             ready = self.select(listening_fds, [], [], 4.0)[0]
             if not ready:
                 # flush empty socket
                 websocket.flush()
             for fd in ready:
                 if fd == websocket_fd:
                     recvmsg = RedisMessage(websocket.receive())
                     if recvmsg:
                         subscriber.publish_message(recvmsg)
                 elif fd == redis_fd:
                     sendmsg = RedisMessage(subscriber.parse_response())
                     if sendmsg and (echo_message or sendmsg != recvmsg):
                         websocket.send(sendmsg)
                 else:
                     logger.error('Invalid file descriptor: {0}'.format(fd))
             if private_settings.WS4REDIS_HEARTBEAT:
                 websocket.send(private_settings.WS4REDIS_HEARTBEAT)
     except WebSocketError as excpt:
         logger.warning('WebSocketError: ', exc_info=sys.exc_info())
         response = http.HttpResponse(status=1001,
                                      content='Websocket Closed')
     except UpgradeRequiredError as excpt:
         logger.info('Websocket upgrade required')
         response = http.HttpResponseBadRequest(status=426, content=excpt)
     except HandshakeError as excpt:
         logger.warning('HandshakeError: ', exc_info=sys.exc_info())
         response = http.HttpResponseBadRequest(content=excpt)
     except PermissionDenied as excpt:
         logger.warning('PermissionDenied: ', exc_info=sys.exc_info())
         response = http.HttpResponseForbidden(content=excpt)
     except Exception as excpt:
         logger.error('Other Exception: ', exc_info=sys.exc_info())
         response = http.HttpResponseServerError(content=excpt)
     else:
         response = http.HttpResponse()
     if websocket:
         websocket.close(code=1001, message='Websocket Closed')
     if hasattr(start_response,
                'im_self') and not start_response.im_self.headers_sent:
         logger.warning('Staring late response on websocket')
         status_text = STATUS_CODE_TEXT.get(response.status_code,
                                            'UNKNOWN STATUS CODE')
         status = '{0} {1}'.format(response.status_code, status_text)
         start_response(force_str(status), response._headers.values())
     logger.info('Finish long living response with status code: '.format(
         response.status_code))
     return response
Ejemplo n.º 4
0
 def __call__(self, environ, start_response):
     """
     Hijack the main loop from the original thread and listen on events on the Redis
     and the Websocket filedescriptors.
     """
     websocket = None
     subscriber = self.Subscriber(self._redis_connection)
     try:
         self.assure_protocol_requirements(environ)
         request = WSGIRequest(environ)
         if callable(private_settings.WS4REDIS_PROCESS_REQUEST):
             private_settings.WS4REDIS_PROCESS_REQUEST(request)
         else:
             self.process_request(request)
         channels, echo_message = self.process_subscriptions(request)
         if callable(private_settings.WS4REDIS_ALLOWED_CHANNELS):
             channels = list(
                 private_settings.WS4REDIS_ALLOWED_CHANNELS(
                     request, channels))
         elif private_settings.WS4REDIS_ALLOWED_CHANNELS is not None:
             try:
                 mod, callback = private_settings.WS4REDIS_ALLOWED_CHANNELS.rsplit(
                     '.', 1)
                 callback = getattr(import_module(mod), callback, None)
                 if callable(callback):
                     channels = list(callback(request, channels))
             except AttributeError:
                 pass
         websocket = self.upgrade_websocket(environ, start_response)
         self._websockets.add(websocket)
         logger.debug('Subscribed to channels: {0}'.format(
             ', '.join(channels)))
         subscriber.set_pubsub_channels(request, channels)
         websocket_fd = websocket.get_file_descriptor()
         listening_fds = [websocket_fd]
         redis_fd = subscriber.get_file_descriptor()
         if redis_fd:
             listening_fds.append(redis_fd)
         subscriber.send_persited_messages(websocket)
         recvmsg = None
         while websocket and not websocket.closed:
             ready = self.select(listening_fds, [], [], 4.0)[0]
             if not ready:
                 # flush empty socket
                 websocket.flush()
             for fd in ready:
                 if fd == websocket_fd:
                     recvmsg = RedisMessage(websocket.receive())
                     if recvmsg:
                         subscriber.publish_message(recvmsg)
                 elif fd == redis_fd:
                     sendmsg = RedisMessage(subscriber.parse_response())
                     if sendmsg and (echo_message or sendmsg != recvmsg):
                         websocket.send(sendmsg)
                 else:
                     logger.error('Invalid file descriptor: {0}'.format(fd))
             # Check again that the websocket is closed before sending the heartbeat,
             # because the websocket can closed previously in the loop.
             if private_settings.WS4REDIS_HEARTBEAT and not websocket.closed:
                 websocket.send(private_settings.WS4REDIS_HEARTBEAT)
             # Remove websocket from _websockets if closed
             if websocket.closed:
                 self._websockets.remove(websocket)
     except WebSocketError as excpt:
         logger.warning('WebSocketError: {}'.format(excpt),
                        exc_info=sys.exc_info())
         response = http.HttpResponse(status=1001,
                                      content='Websocket Closed')
     except UpgradeRequiredError as excpt:
         logger.info('Websocket upgrade required')
         response = http.HttpResponseBadRequest(status=426, content=excpt)
     except HandshakeError as excpt:
         logger.warning('HandshakeError: {}'.format(excpt),
                        exc_info=sys.exc_info())
         response = http.HttpResponseBadRequest(content=excpt)
     except PermissionDenied as excpt:
         logger.warning('PermissionDenied: {}'.format(excpt),
                        exc_info=sys.exc_info())
         response = http.HttpResponseForbidden(content=excpt)
     except Exception as excpt:
         logger.error('Other Exception: {}'.format(excpt),
                      exc_info=sys.exc_info())
         response = http.HttpResponseServerError(content=excpt)
     else:
         response = http.HttpResponse()
     finally:
         subscriber.release()
         if websocket:
             websocket.close(code=1001, message='Websocket Closed')
         else:
             logger.warning('Starting late response on websocket')
             status_text = http_client.responses.get(
                 response.status_code, 'UNKNOWN STATUS CODE')
             status = '{0} {1}'.format(response.status_code, status_text)
             headers = response._headers.values()
             if six.PY3:
                 headers = list(headers)
             start_response(force_str(status), headers)
             logger.info(
                 'Finish non-websocket response with status code: {}'.
                 format(response.status_code))
     return response
Ejemplo n.º 5
0
    def __call__(self, environ, start_response):
        """
        Hijack the main loop from the original thread and listen on events on the Redis
        and the Websocket filedescriptors.
        """
        user_connection = None

        #TODO: also log ip
        logger.info("Got a websocket connection",
                    extra={"environment": environ})

        try:
            self.assure_protocol_requirements(environ)
            request = WSGIRequest(environ)

            session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME,
                                              None)

            websocket = self.upgrade_websocket(environ, start_response)
            user_connection = UserConnection(request, session_key,
                                             self.get_event(), websocket)

            # Every user gets auto-subscribed to the global stream. This is where we broadcast sitewide messages
            user_connection.subscribe("global-events")

            user_connection.websocket_file_descriptor = user_connection.websocket.get_file_descriptor(
            )
            user_connection.subscription_file_descriptor = user_connection.subscription.get_file_descriptor(
            )

            listening_fds = [
                user_connection.websocket_file_descriptor,
                user_connection.subscription_file_descriptor
            ]

            # TODO: if this is a resubscription, we should allow some catch-up mechanism
            while user_connection.connected:
                ready_file_descriptors = self.select(
                    listening_fds, [], [],
                    settings.WEBSOCKET_HEARTBEAT_INTERVAL)[0]
                user_connection.process_file_descriptors(
                    ready_file_descriptors)

        except WebSocketError as excpt:
            logger.warning("WebSocketError: {}".format(excpt),
                           exc_info=sys.exc_info())
            response = http.HttpResponse(status=1001,
                                         content="Websocket Closed")
        except UpgradeRequiredError as excpt:
            logger.info("Websocket upgrade required")
            response = http.HttpResponseBadRequest(
                status=426, content="Websocket upgrade required")
        except HandshakeError as excpt:
            logger.warning('HandshakeError: {}'.format(excpt),
                           exc_info=sys.exc_info())
            response = http.HttpResponseBadRequest(content="Handshake error")
        except PermissionDenied as excpt:
            logger.warning('PermissionDenied: {}'.format(excpt),
                           exc_info=sys.exc_info())
            response = http.HttpResponseForbidden(content="Permission denied!")
        except Exception as excpt:
            logger.error('Other Exception: {}'.format(excpt),
                         exc_info=sys.exc_info())
            response = http.HttpResponseServerError(content="It's broken!")
        else:
            response = http.HttpResponse()
        finally:
            if user_connection:
                user_connection.close()
        return response
Ejemplo n.º 6
0
 def request(self, **request):
     "Construct a generic request object."
     req = WSGIRequest(self._base_environ(**request))
     req.session = {}
     return req
Ejemplo n.º 7
0
class ResultTestCase(TestCase):
    mock_request = WSGIRequest({
            'REQUEST_METHOD': 'GET',
            'wsgi.input': io.StringIO(),
        })
    code = "code234123"
    username = "******"
    teacher_username = "******"
    password = "******"
    player = None
    client: Client = None
    level1: Level = None
    level2: Level = None
    question: Question = None
    result1_level1: Result = None
    result2_level1: Result = None
    result1_level2: Result = None
    result2_level2: Result = None
    id = None
    choice = None

    def setUp(self):
        self.client = Client()
        self.teacher_user = ParlayUser.objects.create_user(
            username=self.teacher_username,
            password=self.password,
            is_teacher=True
        )
        self.assigned_class = Teacher.objects.get(user=self.teacher_user).assigned_class
        self.code = self.assigned_class.code
        self.player_user = ParlayUser.objects.create_user(
            username=self.username,
            password=self.password,
            is_teacher=False,
            class_code=self.code
        )
        self.player = Player.objects.get(user=self.player_user)
        self.level1 = Level.objects.create(
            name="Level 1"
        )
        self.level2 = Level.objects.create(
            name="Level 2"
        )
        self.question = Question.objects.create(
            body='This is a question',
            level=self.level1,
            answer=[0]
        )
        self.choice = Choice.objects.create(body='Choice 1', question=self.question)

        self.question2 = Question.objects.create(
            body='This is a question2',
            level=self.level1,
            answer=[1]
        )
        self.result1_level1 = Result.objects.create(
            level=self.level1,
            distance=100.0,
            player=self.player,
            assigned_class=self.assigned_class
        )
        self.result2_level1 = Result.objects.create(
            level=self.level1,
            distance=200.0,
            player=self.player,
            assigned_class=self.assigned_class
        )
        self.result1_level2 = Result.objects.create(
            level=self.level2,
            distance=300.0,
            player=self.player,
            assigned_class=self.assigned_class
        )
        self.result2_level2 = Result.objects.create(
            level=self.level2,
            distance=150.0,
            player=self.player,
            assigned_class=self.assigned_class,
            award_list=['best_award']
        )

    def tearDown(self):
        self.player_user.delete()

    def result_post_request(self, choice, distance, player, question_id):
        assert_that(self.client.post('/players/%d/results/' % player.id,
                    data={'distance': distance,
                          'level': self.level1.id,
                          'questions': [
                                   {
                                       'question_id': question_id,
                                       'choice_id': choice
                                   }
                               ]},
                         content_type='application/json').status_code, is_(201))

    def test_get_all_results_non_paginated(self):
        res = json.loads(self.client.get('/results/summary/').content)['results']
        assert_that(res[0], has_entries(ResultSerializer.serialize(self.result1_level2)))
        assert_that(res[1], has_entries(ResultSerializer.serialize(self.result2_level1)))
        assert_that(res[2], has_entries(ResultSerializer.serialize(self.result2_level2)))
        assert_that(res[3], has_entries(ResultSerializer.serialize(self.result1_level1)))
        assert_that(res, has_length(4))

    @mock.patch("teacher.views.result_view.PAGE_SIZE", 2)
    def test_get_all_results_paginated(self):
        res = json.loads(self.client.get('/results/summary/?page=%d' % 1).content)['results']
        assert_that(res[0], has_entries(ResultSerializer.serialize(self.result1_level2)))
        assert_that(res[1], has_entries(ResultSerializer.serialize(self.result2_level1)))
        assert_that(res, has_length(2))

    @mock.patch("teacher.views.result_view.PAGE_SIZE", 4)
    def test_paginated_results_same_as_non_paginated_for_all(self):
        res_paginated = json.loads(self.client.get('/results/summary/?page=%d' % 1).content)['results']
        res_non_paginated = json.loads(self.client.get('/results/summary/').content)['results']
        assert_that(res_paginated, equal_to(res_non_paginated))

    def test_get_results_by_level_non_paginated(self):
        res = json.loads(level_views.get_results_by_level(self.mock_request, self.level1.id,
                                                          self.teacher_user).content)['results']
        assert_that(res[0], has_entries(ResultSerializer.serialize(self.result2_level1)))
        assert_that(res[1], has_entries(ResultSerializer.serialize(self.result1_level1)))
        assert_that(res, has_length(2))

    @mock.patch("teacher.views.level_views.PAGE_SIZE", 1)
    def test_get_results_by_level_paginated(self):
        mock_request_with_page = HttpRequest()
        mock_request_with_page.GET.__setitem__('page', 1)
        res = json.loads(level_views.get_results_by_level(mock_request_with_page, self.level1.id,
                                                          self.teacher_user).content)['results']
        assert_that(res[0], has_entries(ResultSerializer.serialize(self.result2_level1)))
        assert_that(res, has_length(1))

    @mock.patch("teacher.views.level_views.PAGE_SIZE", 2)
    def test_paginated_results_same_as_non_paginated_for_level(self):
        mock_request_with_page = WSGIRequest({
            'REQUEST_METHOD': 'GET',
            'wsgi.input': io.StringIO(),
            'page': 1
        })
        res_paginated = json.loads(level_views.get_results_by_level(mock_request_with_page, self.level1.id,
                                                                    self.teacher_user).content)['results']
        res_non_paginated = json.loads(level_views.get_results_by_level(self.mock_request, self.level1.id,
                                                                        self.teacher_user).content)['results']
        assert_that(res_paginated, equal_to(res_non_paginated))

    # negative path test
    def test_get_result_by_level_when_doesnt_include_level(self):
        assert_that(json.loads(level_views.get_results_by_level(self.mock_request, 17,
                                                                self.teacher_user).content)['results'],
                    has_length(0))

    # negative path test
    def test_get_result_by_level_no_level(self):
        assert_that(self.client.get('/levels/results/').status_code, is_(404))

    # negative path test
    @mock.patch("teacher.views.result_view.PAGE_SIZE", 1)
    def test_paginated_page_not_number(self):
        res = json.loads(self.client.get('/results/summary/?page=%s' % 'test').content)['results']
        assert_that(res[0], has_entries(ResultSerializer.serialize(self.result1_level2)))
        assert_that(res, has_length(1))

        # negative path test

    @mock.patch("teacher.views.result_view.PAGE_SIZE", 1)
    def test_paginated_page_not_present(self):
        res = json.loads(self.client.get('/results/summary/?page=%d' % 20).content)['results']
        assert_that(res[0], has_entries(ResultSerializer.serialize(self.result1_level1)))
        assert_that(res, has_length(1))
    
    def test_post_result_without_question_specific_data(self):
        player = Player.objects.create(name="Player2")
        distance = 500.0
        self.client.post('/players/%d/results/' % player.id,
                         data={'distance': distance, 'level': self.level1.id},
                         content_type='application/json')
        result_posted = Result.objects.get(player=player.id)
        result_serialized = ResultSerializer.serialize(result_posted)
        assert_that(result_posted, instance_of(Result))
        assert_that(result_serialized[DISTANCE], is_(distance))
        assert_that(result_serialized[LEVEL], is_(self.level1.id))

    def test_post_result_with_question_specific_data(self):
        player = Player.objects.create(name="Player2")
        distance = 500.0
        choice = 1
        self.result_post_request(choice, distance, player, self.question.id)
        responses = Response.objects.filter(question=self.question)
        assert_that(responses, has_length(1))
        assert_that(responses[0].choice, is_(choice))
        assert_that(responses[0].count, is_(1))

    def test_times_chosen_updates_on_result_post(self):
        player = Player.objects.create(name="Player4")
        initial_times_answered = self.question.times_answered
        initial_times_correct = self.question.times_correct
        choice = 0 # correct choice
        distance = 500.0
        self.result_post_request(choice, distance, player, self.question.id)
        question = Question.objects.get(id=self.question.id)
        # test that times_answered is updated
        updated_times_answered = question.times_answered
        assert_that(initial_times_answered, is_(0))
        assert_that(updated_times_answered, is_(1))
        # test that times_correct is updated
        updated_times_correct = question.times_correct
        assert_that(initial_times_correct, is_(0))
        assert_that(updated_times_correct, is_(1))
        # test that choice times_chosen is updated
        choice = Choice.objects.get(question=self.question.id)
        assert_that(choice.times_chosen, is_(1))
    
    def test_accuracy_updates_on_result_post(self):
        player = Player.objects.create(name="Player3")
        initial_accuracy = player.accuracy
        distance = 500.0
        choice = 1
        self.result_post_request(choice, distance, player, self.question.id)
        updated_accuracy = Player.objects.get(id=player.id).accuracy
        assert_that(initial_accuracy, is_(100))
        assert_that(updated_accuracy, is_(0))
        self.result_post_request(choice, distance, player, self.question2.id)
        updated_accuracy = Player.objects.get(id=player.id).accuracy
        assert_that(updated_accuracy, is_(50))
        self.result_post_request(0, distance, player, self.question.id)
        updated_accuracy = Player.objects.get(id=player.id).accuracy
        assert_that(updated_accuracy, is_((2/3) * 100))

    def test_404_for_post_result(self):
        assert_that(self.client.post('/players/%d/results/' % self.player.id,
                                     data={'distance': 300, 'level': 7},
                                     content_type='application/json').status_code, is_(404))

    def test_404_for_post_result_when_player_not_present(self):
        assert_that(self.client.post('/players/%d/results/' % 315,
                                     data={'distance': 300, 'level': self.level1.id},
                                     content_type='application/json').status_code, is_(404))

    def test_get_results_by_level(self):
        Response.objects.create(question=self.question, choice=0, player=self.player)
        res = json.loads(self.client.get('/players/%d/results/?level=%d' % (self.player.id, self.level1.id))
                         .content)['results']
        assert_that(res[0]['question'], is_(self.question.id))

    def test_get_results_by_level_with_wrong_level(self):
        Response.objects.create(question=self.question, choice=0, player=self.player)
        res = json.loads(self.client.get('/players/%d/results/?level=%d' % (self.player.id, 3))
                         .content)['results']
        assert_that(res, has_length(0))

    def test_404_for_player_not_present_on_get_results_by_level(self):
        assert_that(self.client.get('/players/%d/results/?level=%d' % (958, 3)).status_code, is_(404))
Ejemplo n.º 8
0
 def __init__(self, request=None, locale=None):
     """If request is omitted, fall back to a default locale."""
     self.request = request or WSGIRequest({'REQUEST_METHOD': 'bogus'})
     self.locale, self.shortened_path = split_path(self.request.path_info)
     if locale:
         self.locale = locale