Ejemplo n.º 1
0
    def test_nobody_done(self):
        """If no one finished the survey, counts are zero."""
        survey = Survey.create([], ordinal=1, program_label=self.program_label)
        survey.put()
        kwargs = {
            'key': 'progress',
            'program_label': self.program_label,
            'project_id': 'Project_12345678',
            'cohort_label': '2017_spring',
            'project_cohort_id': 'ProjectCohort_12345678',
            'code': 'trout viper',
            'survey_id': survey.uid,
            'survey_ordinal': survey.ordinal,
        }

        pd = [
            ParticipantData.create(participant_id='Participant_unfinished1',
                                   value=1,
                                   **kwargs),
            ParticipantData.create(participant_id='Participant_unfinished2',
                                   value=1,
                                   **kwargs),
        ]
        ParticipantData.put_multi(pd)

        result = ParticipantData.participation(survey_id=pd[0].survey_id)
        expected = [
            {
                'value': '1',
                'n': 2,
                'survey_ordinal': 1
            },
        ]

        self.assertEqual(result, expected)
Ejemplo n.º 2
0
    def test_put_insert_duplicate(self):
        """put() a new uid but matching an index: raises."""
        params = dict(self.context_params, value='1')
        pd = ParticipantData.create(**params)
        pd.put()

        dupe_params = dict(self.context_params, value='2')
        dupe_pd = ParticipantData.create(**params)

        with self.assertRaises(IntegrityError):
            dupe_pd.put()
Ejemplo n.º 3
0
    def test_put_update_duplicate(self):
        """put() an existing uid but matching an index: raises."""
        params1 = dict(self.context_params, value='1', survey_id='Survey_1')
        pd1 = ParticipantData.create(**params1)
        pd1.put()

        params2 = dict(self.context_params, value='1', survey_id='Survey_2')
        pd2 = ParticipantData.create(**params2)
        pd2.put()

        with self.assertRaises(IntegrityError):
            # Now changing 1 so that it collides with 2.
            pd1.survey_id = 'Survey_2'
            pd1.put()
Ejemplo n.º 4
0
    def test_pd_whitelist(self):
        """Any pd keys other than those whitelisted should not be returned."""
        pid = 'Participant_0123456789ABCDEF'
        context_params = {
            'participant_id': pid,
            'program_label': 'demo-program',
            'project_id': 'Project_12345678',
            'code': 'trout viper',
            'cohort_label': '2017_spring',
            'project_cohort_id': 'ProjectCohort_12345678',
            'survey_id': 'Survey_12345678',
        }
        portal_pd = [
            {
                'key': 'link',  # whitelisted
                'value': '',
            },
            {
                'key': 'not_whitelisted',
                'value': 'secret',
            },
        ]
        portal_pd = [
            ParticipantData.create(**dict(pd, **context_params))
            for pd in portal_pd
        ]
        ParticipantData.put_multi(portal_pd)

        results = ParticipantData.get_by_participant(pid,
                                                     'ProjectCohort_12345678')
        self.assertEqual(len(results), 1)
        self.assertNotEqual(results[0].value, 'secret')
Ejemplo n.º 5
0
    def test_put_for_index_insert_duplicate(self):
        """put_for_index() a new uid but matching an index: succeeds."""
        params = dict(self.context_params, value='1')
        pd = ParticipantData.create(**params)
        pd.put()

        dupe_params = dict(self.context_params, value='2')
        dupe_pd = ParticipantData.create(**params)

        synced_pd = ParticipantData.put_for_index(dupe_pd,
                                                  'participant-survey-key')

        # Returns original uid, not the new one.
        self.assertEqual(synced_pd.uid, pd.uid)

        # Db shows values
        fetched = ParticipantData.get_by_id(pd.uid)
        self.assertEqual(synced_pd.to_dict(), fetched.to_dict())
Ejemplo n.º 6
0
    def test_put_insert(self):
        """put() a new uid: succeeds."""
        params = dict(self.context_params, value='1')
        pd = ParticipantData.create(**params)
        pd.put()

        # Db shows saved values, and db-provided defaults like timestamps
        # are present in the saved object.
        fetched = ParticipantData.get_by_id(pd.uid)
        self.assertEqual(pd.to_dict(), fetched.to_dict())
Ejemplo n.º 7
0
    def test_put_multi(self):
        """If no indexes collide: succeeds, otherwise: raises."""
        params1 = dict(self.context_params, value='1', survey_id='Survey_1')
        pd1 = ParticipantData.create(**params1)

        params2 = dict(self.context_params, value='1', survey_id='Survey_2')
        pd2 = ParticipantData.create(**params2)

        affected_rows = ParticipantData.put_multi([pd1, pd2])

        self.assertEqual(affected_rows, 2)

        self.assertIsNotNone(ParticipantData.get_by_id(pd1.uid))
        self.assertIsNotNone(ParticipantData.get_by_id(pd2.uid))

        pd3 = ParticipantData.create(**params1)

        with self.assertRaises(IntegrityError):
            ParticipantData.put_multi([pd3])
Ejemplo n.º 8
0
def mock_one_finished_one_unfinished(survey_ordinal,
                                     unfinished_id,
                                     finished_id,
                                     pc_id='ProjectCohort_foo',
                                     code='cool cat',
                                     program_label=None,
                                     cohort_label=None,
                                     organization_id=None):
    """Simulating one who finished and one who didn't."""
    survey = Survey.create(
        [],
        ordinal=survey_ordinal,
        program_label=program_label,
        organization_id=organization_id or 'Org_foo',
    )
    survey.put()
    kwargs = {
        'key': 'progress',
        'program_label': program_label,
        'project_id': 'Project_12345678',
        'cohort_label': cohort_label or cohort_label,
        'project_cohort_id': pc_id,
        'code': code,
        'survey_id': survey.uid,
        'survey_ordinal': survey.ordinal,
    }

    pd1 = ParticipantData.create(participant_id=unfinished_id,
                                 value=1,
                                 **kwargs)
    pd2 = ParticipantData.create(participant_id=finished_id, value=1, **kwargs)
    pd3 = ParticipantData.create(participant_id=finished_id,
                                 value=100,
                                 **kwargs)

    return [
        ParticipantData.put_for_index(pd1, 'participant-survey-key'),
        ParticipantData.put_for_index(pd2, 'participant-survey-key'),
        # Writing this third one should should update the second, so the third
        # uid will never get to the db.
        ParticipantData.put_for_index(pd3, 'participant-survey-key'),
    ]
Ejemplo n.º 9
0
    def test_put_for_index_insert(self):
        """put_for_index() a new uid: succeeds."""
        params = dict(self.context_params, value='1')
        pd = ParticipantData.create(**params)
        synced_pd = ParticipantData.put_for_index(pd, 'participant-survey-key')

        # Returns same uid.
        self.assertEqual(pd.uid, synced_pd.uid)

        # Db shows values.
        fetched = ParticipantData.get_by_id(pd.uid)
        self.assertEqual(synced_pd.to_dict(), fetched.to_dict())
Ejemplo n.º 10
0
    def test_put_update(self):
        """put() an exisiting uid: succeeds."""
        params = dict(self.context_params, value='1')
        pd = ParticipantData.create(**params)
        pd.put()

        pd.value = '2'
        pd.put()

        # Db shows values.
        fetched = ParticipantData.get_by_id(pd.uid)
        self.assertEqual(pd.to_dict(), fetched.to_dict())
Ejemplo n.º 11
0
    def test_put_clears_cache(self):
        pc_id = 'ProjectCohort_foo'
        survey_id = 'Survey_foo'
        code = 'foo bar'

        start1 = datetime.datetime.today()
        end1 = start1 + datetime.timedelta(days=1)
        start2 = start1 + datetime.timedelta(days=2)
        end2 = start1 + datetime.timedelta(days=3)

        cache_data = {
            ParticipantData.participation_cache_key(pc_id): {
                ParticipantData.date_key(start1, end1): ['result1'],
                ParticipantData.date_key(start2, end2): ['result2'],
            },
            ParticipantData.participation_cache_key(survey_id): {
                ParticipantData.date_key(start1, end1): ['result1'],
                ParticipantData.date_key(start2, end2): ['result2'],
            },
            ParticipantData.participation_by_pc_cache_key(pc_id): {
                ParticipantData.date_key(start1, end1): ['result1'],
                ParticipantData.date_key(start2, end2): ['result2'],
            },
            ParticipantData.participation_by_pc_cache_key(code): {
                ParticipantData.date_key(start1, end1): ['result1'],
                ParticipantData.date_key(start2, end2): ['result2'],
            },
        }
        memcache.set_multi(cache_data)

        # Write a pd that relates to the pc and survey, falling in the first
        # date range. That date range should clear, the other should remain.
        pd = ParticipantData.create(
            key='progress',
            value=1,
            participant_id='Participant_foo',
            program_label='demo-program',
            project_id='Project_foo',
            cohort_label='2019',
            project_cohort_id=pc_id,
            code=code,
            survey_id=survey_id,
            survey_ordinal=1,
        )
        ParticipantData.put_for_index(pd, 'participant-survey-key')

        for cache_key in cache_data.keys():
            self.assertEqual(len(memcache.get(cache_key)), 1)
    def test_whitelist(self):
        """Certain pd values should readable, other's shouldn't."""
        project_cohort, survey, participant = self.create_pd_context()

        keys = (
            'progress',
            'link',
            'condition',
            'ep_assent',
            'last_login',
            'saw_baseline',
            'saw_demographics',
            'saw_validation',
            'secret',  # NOT on whitelist; should remain secret
        )
        pds = [
            ParticipantData.create(
                key=k,
                value='foo',
                participant_id=participant.uid,
                program_label=self.program_label,
                cohort_label=self.cohort_label,
                project_cohort_id=project_cohort.uid,
                code=project_cohort.code,
                survey_id=survey.uid,
                survey_ordinal=survey.ordinal,
            ) for k in keys
        ]
        ParticipantData.put_multi(pds)

        url = '/api/participants/{}/data?project_cohort_id={}'.format(
            participant.uid, project_cohort.uid)
        result = self.testapp.get(url)
        result_dict = json.loads(result.body)

        self.assertEqual(len(result_dict), len(keys) - 1)

        secret_pd = [pd for pd in result_dict if pd['key'] == 'secret']

        self.assertEqual(len(secret_pd), 0)
Ejemplo n.º 13
0
    def test_create_portal_pd(self, testing=False):
        """Set all the pd potentially required by the portal."""
        # Using the same project and project cohort ids from the mock function.
        context_params = {
            'participant_id': 'Participant_0123456789ABCDEF',
            'program_label': 'demo-program',
            'project_id': 'Project_12345678',
            'cohort_label': '2017_spring',
            'project_cohort_id': 'ProjectCohort_12345678',
            'code': 'trout viper',
            'testing': testing,
        }
        portal_pd = [
            {
                'key': 'link',
                'value': '',
                'survey_id': 'Survey_1',
                'survey_ordinal': 1,
            },
            {
                'key': 'progress',
                'value': '100',
                'survey_id': 'Survey_1',
                'survey_ordinal': 1,
            },
            {
                'key': 'link',
                'value': '',
                'survey_id': 'Survey_2',
                'survey_ordinal': 2,
            },
            {
                'key': 'progress',
                'value': '33',
                'survey_id': 'Survey_2',
                'survey_ordinal': 2,
            },
            {
                'key': 'consent',
                'value': 'true',
                'survey_id': None,
            },
            {
                'key': 'condition',
                'value': 'treatment',
                'survey_id': None,
            },
        ]
        portal_pd = [
            ParticipantData.create(**dict(pd, **context_params))
            for pd in portal_pd
        ]
        ParticipantData.put_multi(portal_pd)

        # Save one more in a different project cohort, since participants
        # have an identity at the organization level.
        other_pc_params = dict(
            context_params,
            project_cohort_id='ProjectCohort_other',
            code='other octopus',
            key='saw_validation',  # N.B. this is whitelisted
            value='bar',
            survey_id='Survey_other',
        )
        ParticipantData.create(**other_pc_params).put()

        return context_params['participant_id']
Ejemplo n.º 14
0
 def test_delete_returns_affected_rows(self):
     params = dict(self.context_params, value='1')
     pd = ParticipantData.create(**params)
     ParticipantData.put(pd)
     affected_rows = ParticipantData.delete_multi([pd])
     self.assertEqual(affected_rows, 1)
    def test_completion_anonymous_allowed(self):
        org_id = 'Organization_foo'
        pc = ProjectCohort.create(
            organization_id=org_id,
            program_label=self.program_label,
            cohort_label=self.cohort_label,
        )
        pc.put()

        today = datetime.datetime.now()
        yesterday = today - datetime.timedelta(days=1)
        tomorrow = today + datetime.timedelta(days=1)

        pd_params = {
            'key': 'progress',
            'value': '100',
            'program_label': self.program_label,
            'cohort_label': self.cohort_label,
            'project_cohort_id': pc.uid,
            'code': pc.code,
            'survey_id': 'Survey_foo',
            'survey_ordinal': 1,
        }

        old_pd = ParticipantData.create(
            created=yesterday.strftime(config.sql_datetime_format),
            modified=yesterday.strftime(config.sql_datetime_format),
            participant_id='Participant_foo',
            **pd_params)
        # Use a lower-level interface so we can set the modified time.
        row = ParticipantData.coerce_row_dict(old_pd.to_dict())
        with mysql_connection.connect() as sql:
            sql.insert_or_update(ParticipantData.table, row)

        current_pd = ParticipantData.create(participant_id='Participant_bar',
                                            **pd_params)
        current_pd.put()

        user = User.create(
            email='*****@*****.**',
            owned_organizations=[org_id],
        )
        user.put()

        result = self.testapp.get(
            '/api/project_cohorts/{}/completion'.format(pc.uid),
            params={
                'start': util.datelike_to_iso_string(today),
                'end': util.datelike_to_iso_string(tomorrow),
            },
            headers=login_headers(user.uid),
            # Authenticated, has permission: 200.
            status=200,
        )

        expected = [{
            'value': '100',
            'survey_ordinal': 1,
            'participant_id': current_pd.participant_id,
        }]
        self.assertEqual(json.loads(result.body), expected)