def test_sync_questions_categories(self, mock_logger, mock_poll_get_flow): self.org = factories.Org() self.poll_1 = factories.Poll(org=self.org, name='Poll 1') self.poll_2 = factories.Poll(org=self.org, name='Poll 2') # Create 2 questions locally: # one that is on RapidPro # and one that should be removed because it won't be on RapidPro self.question_1 = factories.Question( poll=self.poll_1, ruleset_uuid='goodquestion', question_type=models.Question.TYPE_MULTIPLE_CHOICE) self.question_2 = factories.Question( poll=self.poll_1, ruleset_uuid='oldquestion', question_type=models.Question.TYPE_MULTIPLE_CHOICE) # Data to pass to form for testing. Only select one poll self.data = [self.poll_1] # Patch the call to the API flow_1 = mock.Mock() flow_1.uuid = 'abcdefg123' flow_1.name = self.poll_1.name ruleset_existing = mock.Mock() ruleset_existing.uuid = 'goodquestion' ruleset_existing.label = 'good question' ruleset_new = mock.Mock() ruleset_new.uuid = 'newquestion' ruleset_new.label = 'new question' flow_1.rulesets = [ruleset_existing, ruleset_new] # Mock the call to the API to send back a single flow matching our first poll self.mock_temba_client.get_flows.return_value = [flow_1] # Mock this call to return an empty rule set so that RapidPro API is not called mock_poll_get_flow.return_value.rulesets = [] # Assert that the 2 questions exist before we sync when one should be deleted self.assertEqual(models.Question.objects.count(), 2) # Call the task to sync questions... sync_questions_categories(self.org, self.data) # Two questions exist locally, one is new from the RapidPro API mock (flow_1.rulesets) self.assertEqual(models.Question.objects.count(), 2) self.assertEqual(models.Question.objects.first().ruleset_uuid, 'goodquestion') self.assertEqual(models.Question.objects.last().ruleset_uuid, 'newquestion') # Only 1 poll was reflected in the log message as only 1 poll was sent into the form data self.assertEqual(mock_logger.call_count, 2) self.assertIn("1 Poll(s)", mock_logger.call_args[0][0])
def test_from_temba__another_org(self): """Both uuid and Poll must match in order to update existing.""" poll = factories.Poll() other_poll = factories.Poll() other_question = factories.Question(poll=other_poll) ruleset = factories.TembaRuleSet(uuid=other_question.ruleset_uuid) # Should return a Question that is distinct from the existing # Question for another poll. ret_val = models.Question.objects.from_temba(poll, ruleset, order=100) self.assertEqual(models.Question.objects.count(), 2) other_question.refresh_from_db() self.assertNotEqual(ret_val, other_question) self.assertNotEqual(ret_val.poll, other_question.poll) self.assertEqual(ret_val.ruleset_uuid, other_question.ruleset_uuid)
def test_active_poll_selection_and_question_sync(self, mock_sync_questions, mock_sync_poll): """ Test that the poll questions are being synced after the poll form is saved """ self.org = factories.Org() self.poll_1 = factories.Poll(org=self.org) self.poll_2 = factories.Poll(org=self.org) # Data to pass to form for testing. self.data = {'polls': [self.poll_1.id]} self.form = forms.ActivePollsForm(org=self.org, data=self.data) self.assertTrue(self.form.is_valid()) self.form.save() self.assertTrue(mock_sync_questions.delay.called) self.assertEqual(mock_sync_questions.delay.call_args_list[0][0][0], self.org) self.assertEqual(list(mock_sync_questions.delay.call_args_list[0][0][1]), [self.poll_1])
def test_sync__delete_non_existant_poll(self): """Sync should delete Polls that track a flow that does not exist.""" org = factories.Org() poll = factories.Poll(org=org) # noqa self.mock_temba_client.get_flows.return_value = [] models.Poll.objects.sync(org) self.assertEqual(models.Poll.objects.count(), 0)
def test_set_active_for_org__invalid_uuids(self): """An error is raised when an invalid UUID for the org is passed.""" org = factories.Org() poll = factories.Poll(org=org, is_active=False, flow_uuid='a') other_org = factories.Org() other_poll = factories.Poll(org=other_org, is_active=False, flow_uuid='b') with self.assertRaises(ValueError): Poll.objects.set_active_for_org(org, ['a', 'b']) poll.refresh_from_db() self.assertFalse(poll.is_active) other_poll.refresh_from_db() self.assertFalse(other_poll.is_active)
def setUp(self): """Set up common resources.""" super(BaseMapsTest, self).setUp() self.org = factories.Org() self.poll = factories.Poll() self.pollrun = factories.PollRun(poll=self.poll) self.boundary_a = factories.Boundary(org=self.org) self.boundary_b = factories.Boundary(org=self.org)
def test_set_active_for_org(self): """Set which org polls are active.""" polls = [] org = factories.Org() polls.append(factories.Poll(org=org, is_active=True, flow_uuid='0')) polls.append(factories.Poll(org=org, is_active=True, flow_uuid='1')) polls.append(factories.Poll(org=org, is_active=False, flow_uuid='2')) polls.append(factories.Poll(org=org, is_active=False, flow_uuid='3')) other_org = factories.Org() polls.append( factories.Poll(org=other_org, is_active=True, flow_uuid='4')) polls.append( factories.Poll(org=other_org, is_active=False, flow_uuid='5')) models.Poll.objects.set_active_for_org(org, ['0', '2']) # Refresh from database. polls = [models.Poll.objects.get(pk=p.pk) for p in polls] # Specified org Polls should be active. self.assertTrue(polls[0].is_active) self.assertTrue(polls[2].is_active) # All other org polls should be inactive. self.assertFalse(polls[1].is_active) self.assertFalse(polls[3].is_active) # Polls for other orgs should be unaffected. self.assertTrue(polls[4].is_active) self.assertFalse(polls[5].is_active)
def test_from_temba__new(self): """Should create a new Question to match the Poll and uuid.""" poll = factories.Poll() ruleset = factories.TembaRuleSet() # Should create a new Question object that matches the incoming data. question = models.Question.objects.from_temba(poll, ruleset, order=100) self.assertEqual(models.Question.objects.count(), 1) self.assertEqual(question.ruleset_uuid, ruleset.uuid) self.assertEqual(question.poll, poll) self.assertEqual(question.rapidpro_name, ruleset.label) self.assertEqual(question.question_type, models.Question.TYPE_OPEN) self.assertEqual(question.order, 100)
def test_get_flow_definition(self): """Flow definition should be retrieved from the API and cached on the poll.""" definition = factories.TembaFlowDefinition() self.mock_temba_client.get_flow_definition.return_value = definition poll = factories.Poll() self.assertFalse(hasattr(poll, '_flow_definition')) for i in range(2): # The result of the method should be cached on the poll. self.assertEqual(poll.get_flow_definition(), definition) self.assertEqual(poll._flow_definition, definition) # API call count should not go up. self.assertEqual( self.mock_temba_client.get_flow_definition.call_count, 1)
def test_from_temba__existing(self): """Fields on an existing Poll should be updated from RapidPro.""" org = factories.Org() poll = factories.Poll(org=org, flow_uuid='abc', rapidpro_name='old', name='custom', is_active=True) flow = factories.TembaFlow(uuid='abc', name='new') updated = Poll.objects.from_temba(org, flow) poll.refresh_from_db() self.assertEqual(poll.pk, updated.pk) self.assertEqual(poll.rapidpro_name, 'new') self.assertEqual(poll.name, 'custom') self.assertTrue(poll.is_active)
def test_sync__update_existing(self): """Sync should update existing objects if they have changed on RapidPro.""" self.mock_temba_client.get_flow_definition.return_value = factories.TembaFlowDefinition( ) org = factories.Org() poll = factories.Poll(org=org, is_active=True) flow = factories.TembaFlow(uuid=poll.flow_uuid) self.mock_temba_client.get_flows.return_value = [flow] models.Poll.objects.sync(org) self.assertEqual(models.Poll.objects.count(), 1) poll = models.Poll.objects.get() self.assertEqual(poll.org, org) self.assertEqual(poll.flow_uuid, flow.uuid) self.assertEqual(poll.rapidpro_name, flow.name) self.assertEqual(poll.name, flow.name) self.assertTrue(poll.is_active)
def test_from_temba__existing(self): """Should update an existing Question for the Poll and uuid.""" poll = factories.Poll() question = factories.Question(poll=poll, question_type=models.Question.TYPE_OPEN) ruleset = factories.TembaRuleSet( uuid=question.ruleset_uuid, response_type=models.Question.TYPE_MULTIPLE_CHOICE) # Should return the existing Question object. ret_val = models.Question.objects.from_temba(poll, ruleset, order=100) self.assertEqual(ret_val, question) self.assertEqual(ret_val.ruleset_uuid, question.ruleset_uuid) self.assertEqual(models.Question.objects.count(), 1) # Existing Question should be updated to match the incoming data. question.refresh_from_db() self.assertEqual(question.ruleset_uuid, ruleset.uuid) self.assertEqual(question.poll, poll) self.assertEqual(question.rapidpro_name, ruleset.label) self.assertEqual(question.order, 100) # Question type should not be updated. self.assertEqual(question.question_type, models.Question.TYPE_OPEN)
def setUp(self): super(PollChartTest, self).setUp() self.org = factories.Org() self.poll = factories.Poll(org=self.org) self.region1 = factories.Region(org=self.org, name="Beta") self.region2 = factories.Region(org=self.org, name="Acme") self.question1 = factories.Question( poll=self.poll, question_type=models.Question.TYPE_MULTIPLE_CHOICE) self.question2 = factories.Question( poll=self.poll, question_type=models.Question.TYPE_OPEN) self.question3 = factories.Question( poll=self.poll, question_type=models.Question.TYPE_NUMERIC) self.pollrun = factories.UniversalPollRun(poll=self.poll) self.contact1 = factories.Contact(org=self.org, region=self.region1) self.response1 = factories.Response( contact=self.contact1, pollrun=self.pollrun, status=models.Response.STATUS_COMPLETE) factories.Answer( response=self.response1, question=self.question1, value="4.00000", category="1 - 5") factories.Answer( response=self.response1, question=self.question2, value="It's very rainy", category="All Responses") factories.Answer( response=self.response1, question=self.question3, value="4.00000", category="1 - 5") self.contact2 = factories.Contact(org=self.org, region=self.region1) self.response2 = factories.Response( contact=self.contact2, pollrun=self.pollrun, status=models.Response.STATUS_COMPLETE) factories.Answer( response=self.response2, question=self.question1, value="3.00000", category="1 - 5") factories.Answer( response=self.response2, question=self.question2, value="rainy and rainy", category="All Responses") factories.Answer( response=self.response2, question=self.question3, value="3.00000", category="1 - 5") self.contact3 = factories.Contact(org=self.org, region=self.region2) self.response3 = factories.Response( contact=self.contact3, pollrun=self.pollrun, status=models.Response.STATUS_COMPLETE) factories.Answer( response=self.response3, question=self.question1, value="8.00000", category="6 - 10") factories.Answer( response=self.response3, question=self.question2, value="Sunny sunny", category="All Responses") factories.Answer( response=self.response3, question=self.question3, value="8.00000", category="6 - 10") self.pollruns = models.PollRun.objects.filter(pk=self.pollrun.pk) self.responses = models.Response.objects.filter(pollrun=self.pollrun)
def test_by_org(self): """by_org filter should return only Polls for the given org.""" org = factories.Org() poll = factories.Poll(org=org) factories.Poll() self.assertEqual(list(models.Poll.objects.by_org(org)), [poll])
def test_ruleset_uuid_can_repeat_between_polls(self): """ruleset_uuid can be repeated with different Polls.""" factories.Question(poll=factories.Poll(), ruleset_uuid='abc') factories.Question(poll=factories.Poll(), ruleset_uuid='abc')
def test_ruleset_uuid_unique_to_poll(self): """ruleset_uuid should be unique for a particular Poll.""" poll = factories.Poll() factories.Question(poll=poll, ruleset_uuid='abc') with self.assertRaises(IntegrityError): factories.Question(poll=poll, ruleset_uuid='abc')
def test_str(self): """Smoke test for string representation.""" poll = factories.Poll(name='hello') self.assertEqual(str(poll), 'hello')
def test_active(self): """active filter shouldn't return Polls where is_active is False.""" poll = factories.Poll(is_active=True) factories.Poll(is_active=False) self.assertEqual(list(models.Poll.objects.active()), [poll])
def test_flow_uuid_unique_to_org(self): """flow_uuid should be unique for a given Org.""" org = factories.Org() factories.Poll(org=org, flow_uuid='abc') with self.assertRaises(IntegrityError): factories.Poll(org=org, flow_uuid='abc')
def test_flow_uuid_can_repeat_between_orgs(self): """flow_uuid can be repeated with different Orgs.""" factories.Poll(org=factories.Org(), flow_uuid='abc') factories.Poll(org=factories.Org(), flow_uuid='abc')