Example #1
0
    def test_with_app_models(self):
        call_command('create_session', 'simple', '2')

        from .simple.models import Player

        with use_cache():
            players = Player.objects.all()
            self.assertEqual(len(players), 2)

            group = players[0].group
            group.save = Mock()
            group.round_number += 1

            # Query session object to test that it's loaded..
            group.session
            participants = group.session.participant_set.all()

            all_instances = {
                players[0], players[1], group, group.session, participants[0],
                participants[1]
            }

            self.assertEqual(set(_get_save_objects_model_instances()),
                             all_instances)

            # No queries are executed. The group model shall be saved, but we
            # mocked out the save method. All other models should be left
            # untouched.
            with self.assertNumQueries(0):
                save_objects()

            self.assertTrue(group.save.called)
Example #2
0
    def live_method_stuff(self, player_bot, submission):
        PageClass = submission['page_class']
        live_method_name = PageClass.live_method
        if live_method_name:
            record = (player_bot.player.group_id, PageClass)
            if record not in self.executed_live_methods:
                with idmap.use_cache():
                    bots_module = inspect.getmodule(player_bot)
                    method_calls_fn = getattr(bots_module, 'call_live_method',
                                              None)
                    if method_calls_fn:
                        players = {
                            p.id_in_group: p
                            for p in player_bot.group.get_players()
                        }

                        def method(id_in_group, data):
                            return getattr(players[id_in_group],
                                           live_method_name)(data)

                        method_calls_fn(
                            method=method,
                            case=player_bot.case,
                            round_number=player_bot.round_number,
                            page_class=PageClass,
                        )

                self.executed_live_methods.add(record)
Example #3
0
    def test_nested_changes(self):
        call_command('create_session', 'simple', '1')
        # Reset cache.
        with use_cache():
            # Query participant via session.
            session = Session.objects.get()
            participant = session.participant_set.get()
            participant.is_on_wait_page = not participant.is_on_wait_page

            # Save participant.
            with self.assertNumQueries(1):
                save_objects()
Example #4
0
    def test_nested_changes(self):
        call_command('create_session', 'simple', '1')
        # Reset cache.
        with use_cache():
            # Query participant via session.
            session = Session.objects.get()
            participant = session.participant_set.get()
            participant.is_on_wait_page = not participant.is_on_wait_page

            # Save participant.
            with self.assertNumQueries(1):
                save_objects()
Example #5
0
    def test_dont_save_if_no_change(self):
        call_command('create_session', 'simple', '1')

        with use_cache():
            participant = Participant.objects.get()

            # We keep track of the participant.
            instances = _get_save_objects_model_instances()
            self.assertEqual(instances, [participant])

            # But we won't save the participant since we didn't change it.
            with self.assertNumQueries(0):
                save_objects()
Example #6
0
    def test_save_only_changed_fields(self):
        call_command('create_session', 'simple', '1')
        with use_cache():
            participant = Participant.objects.get()
            with mock.patch.object(django.db.models.Model, 'save') as patched_save:
                save_objects()
                # in save-the-change 2017 version, save is not called at all
                patched_save.assert_called_once_with(update_fields=[])

                participant.code = 'hello'
                save_objects()
                # but is this necessarily the only argument? no
                patched_save.assert_called_with(update_fields=['code'])
Example #7
0
    def test_dont_save_if_no_change(self):
        call_command('create_session', 'simple', '1')

        with use_cache():
            participant = Participant.objects.get()

            # We keep track of the participant.
            instances = _get_save_objects_model_instances()
            self.assertEqual(instances, [participant])

            # But we won't save the participant since we didn't change it.
            with self.assertNumQueries(0):
                save_objects()
Example #8
0
    def test_save_only_changed_fields(self):
        call_command('create_session', 'simple', '1')
        with use_cache():
            participant = Participant.objects.get()
            with mock.patch.object(django.db.models.Model,
                                   'save') as patched_save:
                save_objects()
                # in save-the-change 2017 version, save is not called at all
                patched_save.assert_called_once_with(update_fields=[])

                participant.code = 'hello'
                save_objects()
                # but is this necessarily the only argument? no
                patched_save.assert_called_with(update_fields=['code'])
Example #9
0
    def test_not_lazy(self):

        with use_cache():

            page = Page()
            participant = Participant.objects.get()
            # 2 queries: for all objects, and for player_lookup
            with self.assertNumQueries(2):
                page.set_attributes(participant)
            with self.assertNumQueries(0):
                _ = page.player.id
                _ = page.group.id
                _ = page.session.id
                _ = page.subsession.id
                _ = page.participant.id
Example #10
0
    def mock_exogenous_data(self):
        '''
        It's for any exogenous data:
        - participant labels (which are not passed in through REST API)
        - participant vars
        - session vars (if we enable that)
        '''
        if self.config.get('mock_exogenous_data'):
            import shared_out as user_utils

            with idmap.use_cache():
                user_utils.mock_exogenous_data(self)

                # need to save self because it's not in the idmap cache
                self.save()
Example #11
0
    def test_lazy(self):
        with use_cache():
            page = Page()
            participant = Participant.objects.get()
            # set_attributes causes player_lookups

            # only makes 1 query, for player_lookup
            with self.assertNumQueries(1):
                page.set_attributes(participant, lazy=True)
            # query only when we need it
            with self.assertNumQueries(1):
                _ = page.player.id
            # cached in idmap
            with self.assertNumQueries(0):
                _ = page.player.id
Example #12
0
    def test_lazy(self):
        with use_cache():
            page = Page()
            participant = Participant.objects.get()
            # set_attributes causes player_lookups

            # only makes 1 query, for player_lookup
            with self.assertNumQueries(1):
                page.set_attributes(participant, lazy=True)
            # query only when we need it
            with self.assertNumQueries(1):
                _ = page.player.id
            # cached in idmap
            with self.assertNumQueries(0):
                _ = page.player.id
Example #13
0
    def test_not_lazy(self):

        with use_cache():

            page = Page()
            participant = Participant.objects.get()
            # 2 queries: for all objects, and for player_lookup
            with self.assertNumQueries(2):
                page.set_attributes(participant)
            with self.assertNumQueries(0):
                _ = page.player.id
                _ = page.group.id
                _ = page.session.id
                _ = page.subsession.id
                _ = page.participant.id
Example #14
0
    def get(self, request, participant_code):
        participant = get_object_or_404(Participant, code=participant_code)

        if participant._index_in_pages == 0:
            participant._index_in_pages = 1
            participant.visited = True

            # participant.label might already have been set
            participant.label = participant.label or self.request.GET.get(
                otree.constants.participant_label)

            now = django.utils.timezone.now()
            participant.time_started = now
            participant._last_page_timestamp = time.time()
            participant.save()
            with idmap.use_cache():
                player = participant._get_current_player()
                player.start()

        first_url = participant._url_i_should_be_on()
        return HttpResponseRedirect(first_url)
Example #15
0
    def test_strong_refs(self):

        def inside_function():
            '''do these queries in a function so we can know use_strong_refs
            is working correctly
            '''
            player = simple_models.Player.objects.get(
                session_id=self.session_id, id_in_group=1
            )
            player.nonexistent_attribute = 'temp_value'
            group = player.group
            subsession = simple_models.Subsession.objects.get(
                session_id=self.session_id)
            session = player.session
            # do a query rather than FK lookup player.participant
            # to avoid participant from being cached on player
            # we want to make sure it actually goes into the IDmap cache
            participant = session.participant_set.first()

        with use_cache():
            inside_function()
            with self.assertNumQueries(0):
                # if you use get() by PK, it skips the query entirely
                player = simple_models.Player.objects.get(id=self.player_id)
                self.assertEqual(player.nonexistent_attribute, 'temp_value')
                group = player.group
                subsession = player.subsession
                session = player.session
                # this shouldn't do a query because we know the participant PK
                # (it's player.participant_id), and the participant
                # should have been stored in the IDmap cache
                participant = player.participant
            with self.assertNumQueries(1):
                # this does a query because we don't know the pk.
                # but after retrieving the object, it checks the cache
                # if that item already exists.
                player = simple_models.Player.objects.get(
                    session_id=self.session_id, id_in_group=1
                )
Example #16
0
    def test_strong_refs(self):

        def inside_function():
            '''do these queries in a function so we can know use_strong_refs
            is working correctly
            '''
            player = simple_models.Player.objects.get(
                session_id=self.session_id, id_in_group=1
            )
            player.nonexistent_attribute = 'temp_value'
            group = player.group
            subsession = simple_models.Subsession.objects.get(
                session_id=self.session_id)
            session = player.session
            # do a query rather than FK lookup player.participant
            # to avoid participant from being cached on player
            # we want to make sure it actually goes into the IDmap cache
            participant = session.participant_set.first()

        with use_cache():
            inside_function()
            with self.assertNumQueries(0):
                # if you use get() by PK, it skips the query entirely
                player = simple_models.Player.objects.get(id=self.player_id)
                self.assertEqual(player.nonexistent_attribute, 'temp_value')
                group = player.group
                subsession = player.subsession
                session = player.session
                # this shouldn't do a query because we know the participant PK
                # (it's player.participant_id), and the participant
                # should have been stored in the IDmap cache
                participant = player.participant
            with self.assertNumQueries(1):
                # this does a query because we don't know the pk.
                # but after retrieving the object, it checks the cache
                # if that item already exists.
                player = simple_models.Player.objects.get(
                    session_id=self.session_id, id_in_group=1
                )
Example #17
0
    def test_with_app_models(self):
        call_command('create_session', 'simple', '2')

        from .simple.models import Player

        with use_cache():
            players = Player.objects.all()
            self.assertEqual(len(players), 2)

            group = players[0].group
            group.save = Mock()
            group.round_number += 1

            # Query session object to test that it's loaded..
            group.session
            participants = group.session.participant_set.all()

            all_instances = {
                players[0],
                players[1],
                group,
                group.session,
                participants[0],
                participants[1]
            }

            self.assertEqual(
                set(_get_save_objects_model_instances()),
                all_instances)

            # No queries are executed. The group model shall be saved, but we
            # mocked out the save method. All other models should be left
            # untouched.
            with self.assertNumQueries(0):
                save_objects()

            self.assertTrue(group.save.called)
Example #18
0
 def query_and_call():
     with idmap.use_cache():
         new_model = cls.objects.get(id=self.id)
         callback.__func__.__get__(new_model, cls)(*args, **kwargs)
Example #19
0
def live_payload_function(participant_code, page_name, payload):

    participant = Participant.objects.get(code=participant_code)
    lookup = get_page_lookup(participant._session_code,
                             participant._index_in_pages)
    app_name = lookup.app_name
    models_module = otree.common.get_models_module(app_name)
    PageClass = lookup.page_class
    # this could be incorrect if the player advances right after liveSend is executed.
    # maybe just return if it doesn't match. (but leave it in for now and see how much that occurs,
    # don't want silent failures.)
    if page_name != PageClass.__name__:
        logger.warning(
            f'Ignoring liveSend message from {participant_code} because '
            f'they are on page {PageClass.__name__}, not {page_name}.')
        return
    live_method_name = PageClass.live_method

    with idmap.use_cache():
        player = models_module.Player.objects.get(
            round_number=lookup.round_number, participant=participant)

        # it makes sense to check the group first because
        # if the player forgot to define it on the Player,
        # we shouldn't fall back to checking the group. you could get an error like
        # 'Group' has no attribute 'live_auction' which would be confusing.
        # also, we need this 'group' object anyway.
        # and this is a good place to show the deprecation warning.
        group = player.group
        if hasattr(group, live_method_name):
            method = getattr(group, live_method_name)
            retval = method(player.id_in_group, payload)
        else:
            method = getattr(player, live_method_name)
            retval = method(payload)

    if not retval:
        return
    if not isinstance(retval, dict):
        msg = f'{live_method_name} must return a dict'
        raise LiveMethodBadReturnValue(msg)

    pcodes_dict = {
        d['id_in_group']: d['participant__code']
        for d in models_module.Player.objects.filter(
            group=group).values('participant__code', 'id_in_group')
    }

    if 0 in retval:
        if len(retval) > 1:
            raise LiveMethodBadReturnValue(
                'If dict returned by live_method has key 0, it must not contain any other keys'
            )
    else:
        for pid in retval:
            if pid not in pcodes_dict:
                msg = f'live_method has invalid return value. No player with id_in_group={repr(pid)}'
                raise LiveMethodBadReturnValue(msg)

    pcode_retval = {}
    for pid, pcode in pcodes_dict.items():
        payload = retval.get(pid, retval.get(0))
        if payload is not None:
            pcode_retval[pcode] = payload

    _live_send_back(participant._session_code, participant._index_in_pages,
                    pcode_retval)