def set_up(self): """Clear relevant tables from testing SQL database.""" # Let ConsistencyTestCase set up the datastore testing stub. super(TestGraphQLProjectCohort, self).set_up() with mysql_connection.connect() as sql: sql.reset({ 'checkpoint': Checkpoint.get_table_definition(), }) Program.mock_program_config( self.program_label, { 'name': self.program_name, 'default_portal_type': 'name_or_id', 'description': self.program_description, 'cohorts': { self.cohort_label: self.cohort } }) application = webapp2.WSGIApplication(api_routes, config={ 'webapp2_extras.sessions': { 'secret_key': self.cookie_key } }, debug=True) self.testapp = webtest.TestApp(application)
def set_up(self): # Let ConsistencyTestCase set up the datastore testing stub. super(TestApiParticipation, self).set_up() application = webapp2.WSGIApplication(api_routes, config={ 'webapp2_extras.sessions': { 'secret_key': self.cookie_key } }, debug=True) self.testapp = webtest.TestApp(application) # Successful download of completion ids triggers a notification, which # requires a cohort name. Program.mock_program_config( self.program_label, {'cohorts': { self.cohort_label: { 'name': self.cohort_label } }}, ) with mysql_connection.connect() as sql: sql.reset({ 'participant': Participant.get_table_definition(), 'participant_data': ParticipantData.get_table_definition(), })
def set_up(self): # Let ConsistencyTestCase set up the datastore testing stub. super(TestApiAuthentication, self).set_up() application = webapp2.WSGIApplication(api_routes, config={ 'webapp2_extras.sessions': { 'secret_key': self.cookie_key } }, debug=True) self.testapp = webtest.TestApp(application) # Tone down the intense number of hashing rounds for passwords so our # unit tests are fast. User.password_hashing_context.update( sha512_crypt__default_rounds=1000, sha256_crypt__default_rounds=1000, ) # Should be able to register with a legit cohort. Make sure it exists. Program.mock_program_config( self.program_label, { 'name': self.program_name, 'cohorts': { self.cohort_label: { 'name': self.cohort_label } } }, )
def create_project_cohort(self, cohort_date=datetime.datetime.today()): program_label = 'demo-program' cohort_label = 'demo-cohort' program = Program.get_config(program_label) org_id = 'Org_Foo' liaison_id = 'User_liaison' project = Project.create(organization_id=org_id, program_label=program_label) project.put() one_day = datetime.timedelta(days=1) cohort_config = { 'label': cohort_label, 'name': 'Demo Cohort', 'open_date': str(cohort_date - one_day), # yesterday 'close_date': str(cohort_date + one_day), # tomorrow } program['cohorts'][cohort_label] = cohort_config Program.mock_program_config( program_label, {'cohorts': { cohort_label: cohort_config }}, ) pc = ProjectCohort.create( project_id=project.uid, organization_id=org_id, program_label=program_label, cohort_label=cohort_label, liaison_id=liaison_id, ) pc.put() return pc
def test_select_checkpoints_with_offset(self): """Can use queries like "LIMIT 20,10" to get "pages" of records.""" # Create two checkpoints. program_label = 'demo-program' Program.mock_program_config( program_label, { 'project_tasklist_template': [ { 'name': 'Foo', 'label': 'checkpoint_foo', 'tasks': [] }, { 'name': 'Bar', 'label': 'checkpoint_bar', 'tasks': [] }, ] }) project = Project.create(program_label=program_label, organization_id='Organization_Foo') project.put() # Select each of the two checkpoints in different queries with one-row # pages. r1 = Checkpoint.get(program_label=program_label, n=1, offset=0) r2 = Checkpoint.get(program_label=program_label, n=1, offset=1) self.assertNotEqual(r1[0].uid, r2[0].uid)
def create_checkpoints(self): """Checkpoints should gain additional properties as client dicts.""" config = { 'project_tasklist_template': [ { 'name': "Project Foo", 'label': 'demo_project__foo', 'body': "foo", 'tasks': [], }, { 'name': "Project Bar", 'label': 'demo_project__bar', 'body': "bar", 'tasks': [], }, ], } Program.mock_program_config('demo-program', config) checkpoints = ( Checkpoint.create( parent_id='Project_foo', ordinal=1, program_label='demo-program', **config['project_tasklist_template'][0] ), Checkpoint.create( parent_id='Project_bar', ordinal=2, program_label='demo-program', **config['project_tasklist_template'][1] ), ) Checkpoint.put_multi(checkpoints) return checkpoints
def create_project_task(self, cohort_date=datetime.datetime.today()): program_label = 'demo-program' task_label = 'task_project_foo' project = Project.create(program_label=program_label, organization_id='Organization_Foo') task_template = { 'label': task_label, 'data_type': 'radio', 'select_options': [{ 'value': 'normal', 'label': 'true names' }, { 'value': 'alias', 'label': 'aliases' }], } Program.mock_program_config( program_label, {'project_tasklist_template': [{ 'tasks': [task_template] }]}) t = Task.create(task_label, 1, 'checkpoint_foo', parent=project, program_label=program_label) t.put() return t
def test_project_task_body(self): """Tasks should get dynamic properties from their definition.""" program_label = 'demo-program' task_label = 'task_foo' project = Project.create(program_label=program_label, organization_id='Organization_Foo') task_template = { 'label': task_label, 'body': "<p>Demo body.</p>", } Program.mock_program_config( program_label, {'project_tasklist_template': [{ 'tasks': [task_template] }]}) t = Task.create(task_label, 1, 'checkpoint_foo', parent=project, program_label=program_label) t_dict = t.to_client_dict() self.assertIsInstance(t_dict['body'], basestring) self.assertGreater(len(t_dict['body']), 0)
def test_create_select(self): program_label = 'demo-program' task_label = 'task_foo' project = Project.create(program_label=program_label, organization_id='Organization_Foo') task_template = { 'label': task_label, 'data_type': 'radio', 'select_options': [{ 'value': 'normal', 'label': 'true names' }, { 'value': 'alias', 'label': 'aliases' }], } Program.mock_program_config( program_label, {'project_tasklist_template': [{ 'tasks': [task_template] }]}) t = Task.create(task_label, 1, 'checkpoint_foo', parent=project, program_label=program_label) t_dict = t.to_client_dict() self.assertEqual(t_dict['select_options'], task_template['select_options'])
def test_initial_values(self): """Adopt initial values if specified, overriding defaults.""" # Background program_label = 'demo-program' task_label_default = 'task_default' task_label_init = 'task_init' # One task with default values, one with a non-default initial value. task_template_default = { 'label': task_label_default, # default value of disabled is False } task_template_initial_values = { 'label': task_label_init, 'initial_values': { 'disabled': True }, # override default } Program.mock_program_config( program_label, { 'project_tasklist_template': [{ 'tasks': [ task_template_default, task_template_initial_values, ] }] }) # Creating the project will generate a tasklist with the above tasks. project = Project.create(program_label=program_label, organization_id='Organization_Foo') self.assertFalse(project.tasklist.tasks[0].disabled) self.assertTrue(project.tasklist.tasks[1].disabled)
def set_up(self): """Clear relevant tables from testing SQL database.""" # Let ConsistencyTestCase set up the datastore testing stub. super(TestProjectCohort, self).set_up() Program.mock_program_config(self.program_label, { 'default_portal_type': 'name_or_id', })
def test_join_org(self): """Joining an org makes task reminders for all contained tasklists.""" program_label = 'demo-program' cohort_label = 'demo-cohort' # Guarantee the dates will work by mocking the cohort config. cohort_config = { 'label': cohort_label, 'name': 'Demo Cohort', 'open_date': str(datetime.date.today()), 'close_date': str(datetime.date.today()), } Program.mock_program_config( program_label, {'cohorts': { cohort_label: cohort_config }}, ) program = Program.get_config(program_label) tasklist_template = program['surveys'][0]['survey_tasklist_template'] owner = User.create(email='*****@*****.**', user_type='user') org = Organization.create(name="Foo Org", liaison_id=owner.uid) owner.owned_organizations = [org.uid] project = Project.create(program_label=program_label, organization_id=org.uid) survey = Survey.create(tasklist_template, project_id=project.uid, organization_id=org.uid, program_label=program_label, ordinal=1, cohort_label=cohort_label) owner.put() org.put() project.put() survey.put() # The assumption here is the org and its contents are long-standing, # so force consistency with all. org.key.get() project.key.get() survey.key.get() joiner = User.create(email='*****@*****.**', user_type='user') joiner.put() self.testapp.post_json( '/api/users/{}/organizations'.format(joiner.uid), org.to_client_dict(), headers=login_headers(owner.uid), ) # One TaskReminder for each of: org tasklist, project tasklist, survey # tasklist. self.assertEqual(len(TaskReminder.get(ancestor=joiner)), 3) return (org, project, survey, owner, joiner)
def test_queue_org_welcome_back(self): Program.mock_program_config('p1', {'project_tasklist_template': []}) # Case 1: New PC, returning. returning_pc1 = ProjectCohort.create( program_label='p1', organization_id='Organization_returning', project_id='Project_returning', cohort_label='2020', ) returning_pc1.put() returning_pc2 = ProjectCohort.create( program_label='p1', organization_id='Organization_returning', project_id='Project_returning', cohort_label='2019', created=datetime.datetime.now() - datetime.timedelta(days=365)) returning_pc2.put() # Case 2: New PC, but not returning. new_pc = ProjectCohort.create( program_label='p1', organization_id='Organization_new', project_id='Project_new', ) new_pc.put() # Case 3: Old PC (not created in the day). old_pc = ProjectCohort.create( program_label='p1', organization_id='Organization_old', project_id='Project_old', created=datetime.datetime.now() - datetime.timedelta(hours=48), ) old_pc.put() # Some tasks are created on put. We're not interested in these. creation_tasks = self.taskqueue_stub.get_filtered_tasks() templates = [ self.create_mandrill_template('p1-{}'.format( auto_prompt.ORG_WELCOME_BACK_SUFFIX)), ] auto_prompt.queue_org_welcome_back(templates) tasks = self.taskqueue_stub.get_filtered_tasks() num_new_tasks = len(tasks) - len(creation_tasks) # Only the returning pc should have a task queued. self.assertEqual(num_new_tasks, 1) expected_url = '/task/email_project/Project_returning/p1-org-welcome-back' self.assertIn(expected_url, [t.url for t in tasks]) Program.reset_mocks()
def test_override_portal_message(self): label = 'override-program' config = {'override_portal_message': 'Override message.'} Program.mock_program_config(label, config) pc = ProjectCohort.create(program_label=label) self.assertEqual( pc.to_client_dict()['portal_message'], config['override_portal_message'], )
def test_checkpoint_client_dict(self): """Checkpoints should gain additional properties as client dicts.""" checkpoint_template = { 'name': "Project Foo", 'label': 'demo_project__foo', 'body': "foo", 'tasks': [], } config = {'project_tasklist_template': [checkpoint_template]} Program.mock_program_config('demo-program', config) checkpoint = Checkpoint.create(parent_id='Project_foo', ordinal=1, program_label='demo-program', **checkpoint_template) self.assertIsNone(getattr(checkpoint, 'body', None)) self.assertIsNotNone(checkpoint.to_client_dict()['body'])
def set_up(self): # Let ConsistencyTestCase set up the datastore testing stub. super(TestGraphQLProgramCohort, self).set_up() application = webapp2.WSGIApplication( api_routes, config={ 'webapp2_extras.sessions': { 'secret_key': self.cookie_key } }, debug=True ) self.testapp = webtest.TestApp(application) Program.mock_program_config('demo-program', {'cohorts': self.cohorts})
def create_with_project_cohort(self): checkpoint_template = { 'name': "Survey Foo", 'label': 'demo_survey__foo', 'body': "foo", 'tasks': [], } config = { 'surveys': [ { 'name': "Student Module", 'survey_tasklist_template': [checkpoint_template], }, ], } Program.mock_program_config(self.program_label, config) org = Organization.create(name='Foo Org') org.put() project = Project.create( program_label=self.program_label, organization_id=org.uid, ) project.put() pc = ProjectCohort.create( program_label=self.program_label, organization_id=org.uid, project_id=project.uid, ) pc.put() checkpoint = Checkpoint.create(parent_id='Survey_foo', ordinal=1, program_label=self.program_label, organization_id=org.uid, project_id=project.uid, project_cohort_id=pc.uid, status='incomplete', **checkpoint_template) checkpoint.put() pc.update_cached_properties() return org, project, pc, checkpoint
def test_join_cohort(self, cohort_date=datetime.date.today()): """Allowed for org admin owner of project.""" # Existing things to relate to. program_label = 'demo-program' cohort_label = 'demo-cohort' program = Program.get_config(program_label) org_id = 'Org_Foo' user = User.create(email="*****@*****.**", owned_organizations=[org_id]) project = Project.create(organization_id=org_id, program_label=program_label) user.put() project.put() # Guarantee the dates will work by mocking the cohort config. one_day = datetime.timedelta(days=1) cohort_config = { 'label': cohort_label, 'name': 'Demo Cohort', 'open_date': str(cohort_date - one_day), # yesterday 'close_date': str(cohort_date + one_day), # tomorrow } program['cohorts'][cohort_label] = cohort_config Program.mock_program_config( program_label, {'cohorts': {cohort_label: cohort_config}}, ) # Create the project cohort through the api. Any response other than # 200 will fail the test. response = self.testapp.post_json( '/api/project_cohorts', { 'project_id': project.uid, 'organization_id': org_id, 'program_label': program_label, 'cohort_label': cohort_label, 'liaison_id': user.uid, }, headers=login_headers(user.uid) ) response_dict = json.loads(response.body) return (ProjectCohort.get_by_id(response_dict['uid']), user)
def set_up(self): """Clear relevant tables from testing SQL database.""" # Let ConsistencyTestCase set up the datastore testing stub. super(TestGraphQL, self).set_up() Program.mock_program_config(self.program_label, { 'default_portal_type': 'name_or_id', }) application = webapp2.WSGIApplication(api_routes, config={ 'webapp2_extras.sessions': { 'secret_key': self.cookie_key } }, debug=True) self.testapp = webtest.TestApp(application)
def test_dashboard_unlisted(self): """Some programs support other apps and aren't meant to be queried.""" # See #1015 Program.mock_program_config('ep19', {'listed': False}) user = User.create(email='*****@*****.**', user_type='super_admin') user.put() pc = ProjectCohort.create( program_label='ep19', organization_id='Org_foo', ) pc.put() response = self.testapp.get('/api/dashboard?program_label=ep19', headers=login_headers(user.uid)) self.assertEqual(response.body, '[]')
def test_queue_org_welcome(self): Program.mock_program_config('p1', {'project_tasklist_template': []}) Program.mock_program_config('p2', {'project_tasklist_template': []}) old_project = Project.create( program_label='p1', organization_id='Organization_foo', created=datetime.datetime.now() - datetime.timedelta(hours=48), ) old_project.put() new_project = Project.create( program_label='p1', organization_id='Organization_foo', ) new_project.put() other_project = Project.create( program_label='p2', # no matching template organization_id='Organization_foo', ) other_project.put() templates = [ self.create_mandrill_template('p1-{}'.format( auto_prompt.ORG_WELCOME_SUFFIX)), self.create_mandrill_template('foo-template'), ] auto_prompt.queue_org_welcome(templates) tasks = self.taskqueue_stub.get_filtered_tasks() # Only the recently created project, which also has a org welcome # template, should be queued. The old project, and the project on the # other program, should not be welcomed. self.assertEqual(len(tasks), 1) expected_url = '/task/email_project/{}/p1-org-welcome'.format( new_project.uid) self.assertIn(expected_url, [t.url for t in tasks]) Program.reset_mocks()
def test_custom_sender(self): # Mock a program that defines a special contact email address. program_label = 'ep' sender = '*****@*****.**' Program.mock_program_config( program_label, { 'name': 'Engagement Project', 'contact_email_address': sender, }, ) email_addr = '*****@*****.**' response = self.testapp.post_json( '/api/register', { 'domain': 'https://copilot.perts.net', 'platform': 'triton', 'email': email_addr, 'program_label': program_label, }, status=204, ) # Email was created with from/reply properties. emails = Email.get(to_address=email_addr) email = emails[0] self.assertEqual( email.mandrill_template_content['contact_email_address'], sender, ) self.assertEqual(email.from_address, sender) self.assertEqual(email.reply_to, sender) # Should be hard-coded in api_helper self.assertEqual(email.from_name, 'Copilot')
def test_checklist_nudge(self): month_from_now = util.datelike_to_iso_string(datetime.date.today() + datetime.timedelta( days=30)) Program.mock_program_config( 'p1', { 'cohorts': { '2019': { 'label': '2019', 'open_date': '2019-06-01' }, '2020': { 'label': '2020', 'open_date': month_from_now }, }, 'project_tasklist_template': [] }, ) Program.mock_program_config( 'p2', { 'cohorts': {}, 'project_tasklist_template': [] }, ) templates = [ self.create_mandrill_template('p1-{}'.format( auto_prompt.CHECKLIST_NUDGE_SUFFIX)), ] # Case 1: 2020 PCs gets prompt current_pc1 = ProjectCohort.create( program_label='p1', organization_id='Organization_foo', project_id='Project_current1', cohort_label='2020', ) current_pc1.put() current_pc2 = ProjectCohort.create( program_label='p1', organization_id='Organization_bar', project_id='Project_current2', cohort_label='2020', ) current_pc2.put() # Case 2: 2019 PC does not old_pc = ProjectCohort.create( program_label='p1', cohort_label='2019', project_id='Project_old', ) old_pc.put() # Case 3: PC in other program does not other_pc = ProjectCohort.create( program_label='p2', cohort_label='2020', project_id='Project_other', ) other_pc.put() # Some tasks are created on put. We're not interested in these. creation_tasks = self.taskqueue_stub.get_filtered_tasks() auto_prompt.queue_checklist_nudge(templates) tasks = self.taskqueue_stub.get_filtered_tasks() num_new_tasks = len(tasks) - len(creation_tasks) # Only the 2 2020 pcs in the right program should have a task queued. self.assertEqual(num_new_tasks, 2) expected_url1 = '/task/email_project/Project_current1/p1-checklist-nudge' self.assertIn(expected_url1, [t.url for t in tasks]) expected_url2 = '/task/email_project/Project_current2/p1-checklist-nudge' self.assertIn(expected_url2, [t.url for t in tasks]) Program.reset_mocks()