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_get_answers(self): """Function should return all Answers that are associated with a Boundary.""" region_a1 = self._create_region(self.boundary_a) region_a2 = self._create_region(self.boundary_a) region_b = self._create_region(self.boundary_b) answer1 = self._create_answer(region=region_a1) answer2 = self._create_answer(region=region_a2) answer3 = self._create_answer(region=region_b) answer4 = self._create_answer(region=region_b) self._create_answer(boundary=None) # not in results - no boundary self._create_answer( # not in results - for another question question=factories.Question(poll=self.poll), response=answer1.response) answers = maps.get_answers(self.pollrun.responses.all(), self.question) self.assertEqual(len(answers), 4, answers) self.assertIn(answer1, answers) self.assertIn(answer2, answers) self.assertIn(answer3, answers) self.assertIn(answer4, answers) # Each answer should have the boundary annotated. self.assertEqual(answers.get(pk=answer1.pk).boundary, self.boundary_a.pk) self.assertEqual(answers.get(pk=answer2.pk).boundary, self.boundary_a.pk) self.assertEqual(answers.get(pk=answer3.pk).boundary, self.boundary_b.pk) self.assertEqual(answers.get(pk=answer4.pk).boundary, self.boundary_b.pk)
def test_categorize(self): rules = [ { 'category': { 'base': 'dogs' }, 'test': { 'type': 'between', 'min': 1, 'max': 3 } }, { 'category': { 'base': 'cats' }, 'test': { 'type': 'number' }, }, ] question = factories.Question(json_rules=json.dumps(rules)) self.assertEqual(question.categorize(2), 'dogs') self.assertEqual(question.categorize(5), 'cats') self.assertEqual(question.categorize("foo"), 'Other')
def test_multiple_choice(self): """Test expected response with a full slate of answers.""" region_a1 = self._create_region(self.boundary_a) region_a2 = self._create_region(self.boundary_a) region_b = self._create_region(self.boundary_b) self._create_answer(region=region_a1, category="red") self._create_answer(region=region_a2, category="red") self._create_answer(region=region_b, category="red") self._create_answer(region=region_b, category="orange") self._create_answer(region=region_b, category="foo") self._create_answer(region=region_b, category="foo") self._create_answer( # ignored - no boundary boundary=None, category="foo2") self._create_answer( # ignored - from another question question=factories.Question(poll=self.poll), region=region_a1, category="bar") data = maps.get_map_data(self.pollrun.responses.all(), self.question) self.assertEqual(set(data), set(('all-categories', 'map-data'))) self.assertEqual(data['all-categories'], ['orange', 'red', 'purple', 'foo', 'Other']) self.assertEqual(data['map-data'], { self.boundary_a.pk: { 'category': 'red', }, self.boundary_b.pk: { 'category': 'foo', }, })
def test_numeric(self): """Test expected response with a full slate of answers.""" region_a1 = self._create_region(self.boundary_a) region_a2 = self._create_region(self.boundary_a) region_b = self._create_region(self.boundary_b) self._create_answer(region=region_a1, category="1-5", value="2") self._create_answer(region=region_a2, category=">5", value="6") self._create_answer(region=region_b, category="1-5", value="4") self._create_answer(region=region_b, category="foo", value="8") self._create_answer( # ignored - no boundary boundary=None, category=">5", value="6") self._create_answer( # ignored - from another question question=factories.Question(poll=self.poll), region=region_a1, category="zero", value="0") data = maps.get_map_data(self.pollrun.responses.all(), self.question) self.assertEqual(set(data), set(('all-categories', 'map-data'))) self.assertEqual(data['all-categories'], ['1-5', '>5', 'foo', 'Other']) self.assertEqual(data['map-data'], { self.boundary_a.pk: { 'average': '4.00', # (2 + 6) / 2 'category': '1-5', }, self.boundary_b.pk: { 'average': '6.00', # (4 + 8) / 2 'category': '>5', }, })
def setUp(self): super(TestCategoryMapData, self).setUp() self.question = factories.Question( poll=self.poll, question_type=models.Question.TYPE_MULTIPLE_CHOICE, rules=[ {'category': 'orange'}, {'category': 'red'}, {'category': 'purple'}, ])
def setUp(self): super(TestNumericMapData, self).setUp() self.question = factories.Question( poll=self.poll, question_type=models.Question.TYPE_NUMERIC, rules=[ { 'category': {'base': '1-5'}, 'test': {'type': 'between', 'min': '1', 'max': '5'}, }, { 'category': {'base': '>5'}, 'test': {'type': 'gt', 'test': '5'}, }, ])
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_guess_question_type_multiple_choice(self): """Guess MULTIPLE_CHOICE if not all rules are numeric.""" question = factories.Question(json_rules=json.dumps([ { 'test': { 'type': 'number' } }, { 'test': { 'type': 'text' } }, ])) self.assertEqual(question.guess_question_type(), models.Question.TYPE_MULTIPLE_CHOICE)
def test_guess_question_type_numeric(self): """Guess NUMERIC if rule types are all numeric.""" question = factories.Question(json_rules=json.dumps([ { 'test': { 'type': 'number' } }, { 'test': { 'type': 'number' } }, ])) self.assertEqual(question.guess_question_type(), models.Question.TYPE_NUMERIC)
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 test_active(self): """is_active() queryset filter should not return Questions with is_active=False.""" question = factories.Question(is_active=True) factories.Question(is_active=False) self.assertEqual(list(models.Question.objects.active()), [question])
def test_guess_question_type_open(self): """Guess OPEN if there are no rules.""" question = factories.Question(json_rules=json.dumps([])) self.assertEqual(question.guess_question_type(), models.Question.TYPE_OPEN)
def setUp(self): super(TestOpenEndedMapData, self).setUp() self.question = factories.Question( poll=self.poll, question_type=models.Question.TYPE_OPEN, rules=[])
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.""" question = factories.Question(name='hello') self.assertEqual(str(question), 'hello')
def setUp(self): super(TestGetAnswers, self).setUp() self.question = factories.Question(poll=self.poll)
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 setUp(self): super(TestChartBaseline, self).setUp() self.org = factories.Org() self.contact1 = factories.Contact(org=self.org, name="Apple") self.contact2 = factories.Contact(org=self.org, name="Blueberry") self.contact3 = factories.Contact(org=self.org, name="Cherry") self.start_date = datetime.datetime(2015, 1, 1, 8, tzinfo=pytz.utc) self.baseline = factories.Question(poll__org=self.org) self.baseline_pollrun1 = factories.UniversalPollRun( poll=self.baseline.poll, conducted_on=self.start_date) self.baseline_pollrun2 = factories.UniversalPollRun( poll=self.baseline.poll, conducted_on=self.start_date + relativedelta(days=1)) self.follow_up = factories.Question(poll__org=self.org) self.follow_up_pollrun1 = factories.UniversalPollRun( poll=self.follow_up.poll, conducted_on=self.start_date + relativedelta(days=1)) self.follow_up_pollrun2 = factories.UniversalPollRun( poll=self.follow_up.poll, conducted_on=self.start_date + relativedelta(days=2)) self.follow_up_pollrun3 = factories.UniversalPollRun( poll=self.follow_up.poll, conducted_on=self.start_date + relativedelta(days=3)) self.baseline_term = BaselineTerm.objects.create( org=self.org, name="Test Baseline Term", start_date=self.start_date, end_date=self.start_date + relativedelta(days=3), baseline_poll=self.baseline.poll, baseline_question=self.baseline, follow_up_poll=self.follow_up.poll, follow_up_question=self.follow_up, y_axis_title="# cats") # Create an answer for each contact. contacts = [self.contact1, self.contact2, self.contact3] for i, contact in enumerate(contacts, 1): for j, pollrun in enumerate(self.baseline.poll.pollruns.all(), 1): factories.Answer(response__contact=contact, response__pollrun=pollrun, question=self.baseline, value=10 * i * j, submitted_on=self.start_date + relativedelta(days=j - 1)) for j, pollrun in enumerate(self.follow_up.poll.pollruns.all(), 1): factories.Answer(response__contact=contact, response__pollrun=pollrun, question=self.follow_up, value=7 * i * j, submitted_on=self.start_date + relativedelta(days=j)) # Empty filter form for testing. self.filter_form = BaselineTermFilterForm( org=self.org, baseline_term=self.baseline_term, data_regions=None)