示例#1
0
    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])
示例#2
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)
示例#3
0
 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')
示例#4
0
    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',
            },
        })
示例#5
0
    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',
            },
        })
示例#6
0
 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'},
         ])
示例#7
0
 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'},
             },
         ])
示例#8
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)
示例#9
0
 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)
示例#10
0
 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)
示例#11
0
    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)
示例#12
0
 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])
示例#13
0
 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)
示例#14
0
 def setUp(self):
     super(TestOpenEndedMapData, self).setUp()
     self.question = factories.Question(
         poll=self.poll,
         question_type=models.Question.TYPE_OPEN,
         rules=[])
示例#15
0
 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')
示例#16
0
 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')
示例#17
0
 def test_str(self):
     """Smoke test for string representation."""
     question = factories.Question(name='hello')
     self.assertEqual(str(question), 'hello')
示例#18
0
 def setUp(self):
     super(TestGetAnswers, self).setUp()
     self.question = factories.Question(poll=self.poll)
示例#19
0
    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)
示例#20
0
    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)