<commit_before>from datetime import datetime, time, date, timedelta
import pytz
from copy import deepcopy

import json
import pymongo
from bson.objectid import ObjectId
from bson.timestamp import Timestamp

from twisted.trial.unittest import TestCase
from twisted.internet.defer import inlineCallbacks

from vumi.tests.utils import get_stubbed_worker, UTCNearNow, RegexMatcher

from vusion.dialogue_worker import DialogueWorker
from vusion.utils import time_to_vusion_format, time_from_vusion_format
from vusion.error import MissingData, MissingTemplate
from vusion.persist.action import (
    UnMatchingAnswerAction, EnrollingAction,
    FeedbackAction, SmsMoAction, OptinAction, OptoutAction,
    TaggingAction, ProfilingAction,
    OffsetConditionAction, RemoveRemindersAction,
    ResetAction, RemoveDeadlineAction,
    DelayedEnrollingAction,
    ProportionalTagging, ProportionalLabelling,
    action_generator, Actions, UrlForwarding, SmsForwarding, SmsInviteAction,
    SaveContentVariableTable)
from vusion.context import Context
from vusion.persist import Dialogue, DialogueHistory

from tests.utils import MessageMaker, DataLayerUtils, ObjectMaker
from vusion.tests.test_dialogue_worker import DialogueWorkerTestCase


class DialogueWorkerTestCase_runAction(DialogueWorkerTestCase):

    def test_run_action_unmatching_answer(self):
        self.initialize_properties()

        self.collections['participants'].save(self.mkobj_participant(
            '08',
            tags=['geek'],
            profile=[{'label': 'name',
                     'value': 'Oliv'}]))

        ## Error message
        saved_template_id = self.collections['templates'].save(
            self.template_unmatching_answer)
        self.collections['program_settings'].save(
            {'key': 'default-template-unmatching-answer',
             'value': saved_template_id})

        context = Context()
        context.update({'request-id': '1'})

        self.worker.run_action(
            '08',
            UnMatchingAnswerAction(**{'answer': 'best'}),
            context,
            '1')
        messages = self.app_helper.get_dispatched_outbound()
        self.assertEqual(len(messages), 1)
        self.assertEqual(self.collections['history'].count(), 1)
        history = self.collections['history'].find_one()
        self.assertEqual(history['participant-session-id'], '1')
        self.assertEqual(history['participant-phone'], '08')
        self.assertEqual(history['message-content'],
                         "best does not match any answer")

    @inlineCallbacks
    def test_run_action_tagging(self):
        self.initialize_properties()

        dNow = self.worker.get_local_time()
        dFuture = dNow + timedelta(minutes=30)

        self.collections['participants'].save(self.mkobj_participant(
            '08',
            tags=['geek'],
            profile=[{'label': 'name',
                     'value': 'Oliv'}]))

        ## tagging might make the participant eligible
        unattach_msg = self.mkobj_unattach_message(
            content='Hello',
            send_to_type='match',
            send_to_match_operator='all',
            send_to_match_conditions=['my tag'],
            fixed_time=time_to_vusion_format(dFuture))
        self.collections['unattached_messages'].save(unattach_msg)

        ## Tagging
        yield self.worker.run_action("08", TaggingAction(**{'tag': 'my tag'}))
        yield self.worker.run_action("08", TaggingAction(**{'tag': 'my second tag'}))
        self.assertTrue(self.collections['participants'].find_one({'tags': 'my tag'}))
        yield self.worker.run_action("08", TaggingAction(**{'tag': 'my tag'}))
        self.assertEqual(
            ['geek', 'my tag', 'my second tag'],
            self.collections['participants'].find_one({'tags': 'my tag'})['tags'])
        self.assertEqual(1, self.collections['schedules'].find({'participant-phone': '08'}).count())

    @inlineCallbacks
    def test_run_action_profiling(self):
        self.initialize_properties()

        dNow = self.worker.get_local_time()
        dFuture = dNow + timedelta(minutes=30)

        self.collections['participants'].save(self.mkobj_participant(
            '08',
            tags=['geek'],
            profile=[{'label': 'name',
                     'value': 'Oliv'}]))

        ## tagging might make the participant eligible
        unattach_msg = self.mkobj_unattach_message(
            content='Hello',
            send_to_type='match',
            send_to_match_operator='all',
            send_to_match_conditions=['gender:Female'],
            fixed_time=time_to_vusion_format(dFuture))
        self.collections['unattached_messages'].save(unattach_msg)

        yield self.worker.run_action("08",
                                     ProfilingAction(**{
                                         'label': 'gender',
                                         'value': 'Female'}))
        self.assertTrue(self.collections['participants'].find_one({'profile.label': 'gender'}))
        self.assertTrue(self.collections['participants'].find_one({'profile.value': 'Female'}))
        self.assertEqual(1, self.collections['schedules'].find({'participant-phone':'08'}).count())

    @inlineCallbacks
    def test_run_action_feedback(self):
        self.initialize_properties()

        self.collections['participants'].save(self.mkobj_participant())

        context = Context()
        context.update({'request-id': '1'})

        self.worker.run_action(
            '06',
            FeedbackAction(**{'content': 'message'}),
            context,
            '1')
        messages = yield self.app_helper.get_dispatched_outbound()
        self.assertEqual(len(messages), 1)
        self.assertEqual(self.collections['history'].count(), 1)
        history = self.collections['history'].find_one()
        self.assertEqual(history['participant-session-id'], '1')
        self.assertEqual(history['participant-phone'], '06')

    @inlineCallbacks
    def test_run_action_feedback_simulated(self):
        self.initialize_properties()

        participant = self.mkobj_participant()
        participant['simulate'] = True
        self.collections['participants'].save(participant)

        context = Context()
        context.update({'request-id': '1'})

        self.worker.run_action(
            '06',
            FeedbackAction(**{'content': 'message'}),
            context,
            '1')
        messages = yield self.app_helper.get_dispatched_outbound()
        self.assertEqual(len(messages), 0)
        self.assertEqual(self.collections['history'].count(), 1)
        history = self.collections['history'].find_one()
        self.assertEqual(history['participant-session-id'], '1')
        self.assertEqual(history['participant-phone'], '06')

    @inlineCallbacks
    def test_run_action_sms_mo(self):
        self.initialize_properties()

        self.collections['participants'].save(self.mkobj_participant())

        context = Context()
        context.update({'request-id': '1'})

        self.worker.run_action(
            '06',
            SmsMoAction(**{'mo-content': 'test incoming MO message'}),
            context,
            '1')
        #messages = yield self.app_helper.get_dispatched_outbound()
        messages = yield self.app_helper.get_dispatched_inbound("hi")
        self.assertEqual(len(messages), 1)
        #self.assertEqual(self.collections['history'].count(), 1)
        #history = self.collections['history'].find_one()
        #self.assertEqual(history['participant-session-id'], '1')
        #self.assertEqual(history['participant-phone'], '06')

    @inlineCallbacks
    def test_run_action_enroll(self):
        self.initialize_properties()

        dNow = self.worker.get_local_time()
        self.collections['participants'].save(self.mkobj_participant(
            "08", last_optin_date=time_to_vusion_format(dNow)))        
        self.collections['dialogues'].save(
            self.mkobj_dialogue_question_offset_days())
        dBegin = self.worker.get_local_time()
     
        yield self.worker.run_action("08", EnrollingAction(**{'enroll': '01'}))
        participant = self.collections['participants'].find_one({'enrolled.dialogue-id': '01'})
        self.assertTrue(participant)
        self.assertEqual(1, self.collections['schedules'].count())
        self.assertTrue('date-time' in participant['enrolled'][0])
        dEnrolled = time_from_vusion_format(participant['enrolled'][0]['date-time'])
        self.assertTrue(dEnrolled - dBegin < timedelta(seconds=1))

        #Enrolling again should keep the old date<commit_msg>commented out the tests<commit_after>from datetime import datetime, time, date, timedelta
import pytz
from copy import deepcopy

import json
import pymongo
from bson.objectid import ObjectId
from bson.timestamp import Timestamp

from twisted.trial.unittest import TestCase
from twisted.internet.defer import inlineCallbacks

from vumi.tests.utils import get_stubbed_worker, UTCNearNow, RegexMatcher

from vusion.dialogue_worker import DialogueWorker
from vusion.utils import time_to_vusion_format, time_from_vusion_format
from vusion.error import MissingData, MissingTemplate
from vusion.persist.action import (
    UnMatchingAnswerAction, EnrollingAction,
    FeedbackAction, SmsMoAction, OptinAction, OptoutAction,
    TaggingAction, ProfilingAction,
    OffsetConditionAction, RemoveRemindersAction,
    ResetAction, RemoveDeadlineAction,
    DelayedEnrollingAction,
    ProportionalTagging, ProportionalLabelling,
    action_generator, Actions, UrlForwarding, SmsForwarding, SmsInviteAction,
    SaveContentVariableTable)
from vusion.context import Context
from vusion.persist import Dialogue, DialogueHistory

from tests.utils import MessageMaker, DataLayerUtils, ObjectMaker
from vusion.tests.test_dialogue_worker import DialogueWorkerTestCase


class DialogueWorkerTestCase_runAction(DialogueWorkerTestCase):

    def test_run_action_unmatching_answer(self):
        self.initialize_properties()

        self.collections['participants'].save(self.mkobj_participant(
            '08',
            tags=['geek'],
            profile=[{'label': 'name',
                     'value': 'Oliv'}]))

        ## Error message
        saved_template_id = self.collections['templates'].save(
            self.template_unmatching_answer)
        self.collections['program_settings'].save(
            {'key': 'default-template-unmatching-answer',
             'value': saved_template_id})

        context = Context()
        context.update({'request-id': '1'})

        self.worker.run_action(
            '08',
            UnMatchingAnswerAction(**{'answer': 'best'}),
            context,
            '1')
        messages = self.app_helper.get_dispatched_outbound()
        self.assertEqual(len(messages), 1)
        self.assertEqual(self.collections['history'].count(), 1)
        history = self.collections['history'].find_one()
        self.assertEqual(history['participant-session-id'], '1')
        self.assertEqual(history['participant-phone'], '08')
        self.assertEqual(history['message-content'],
                         "best does not match any answer")

    @inlineCallbacks
    def test_run_action_tagging(self):
        self.initialize_properties()

        dNow = self.worker.get_local_time()
        dFuture = dNow + timedelta(minutes=30)

        self.collections['participants'].save(self.mkobj_participant(
            '08',
            tags=['geek'],
            profile=[{'label': 'name',
                     'value': 'Oliv'}]))

        ## tagging might make the participant eligible
        unattach_msg = self.mkobj_unattach_message(
            content='Hello',
            send_to_type='match',
            send_to_match_operator='all',
            send_to_match_conditions=['my tag'],
            fixed_time=time_to_vusion_format(dFuture))
        self.collections['unattached_messages'].save(unattach_msg)

        ## Tagging
        yield self.worker.run_action("08", TaggingAction(**{'tag': 'my tag'}))
        yield self.worker.run_action("08", TaggingAction(**{'tag': 'my second tag'}))
        self.assertTrue(self.collections['participants'].find_one({'tags': 'my tag'}))
        yield self.worker.run_action("08", TaggingAction(**{'tag': 'my tag'}))
        self.assertEqual(
            ['geek', 'my tag', 'my second tag'],
            self.collections['participants'].find_one({'tags': 'my tag'})['tags'])
        self.assertEqual(1, self.collections['schedules'].find({'participant-phone': '08'}).count())

    @inlineCallbacks
    def test_run_action_profiling(self):
        self.initialize_properties()

        dNow = self.worker.get_local_time()
        dFuture = dNow + timedelta(minutes=30)

        self.collections['participants'].save(self.mkobj_participant(
            '08',
            tags=['geek'],
            profile=[{'label': 'name',
                     'value': 'Oliv'}]))

        ## tagging might make the participant eligible
        unattach_msg = self.mkobj_unattach_message(
            content='Hello',
            send_to_type='match',
            send_to_match_operator='all',
            send_to_match_conditions=['gender:Female'],
            fixed_time=time_to_vusion_format(dFuture))
        self.collections['unattached_messages'].save(unattach_msg)

        yield self.worker.run_action("08",
                                     ProfilingAction(**{
                                         'label': 'gender',
                                         'value': 'Female'}))
        self.assertTrue(self.collections['participants'].find_one({'profile.label': 'gender'}))
        self.assertTrue(self.collections['participants'].find_one({'profile.value': 'Female'}))
        self.assertEqual(1, self.collections['schedules'].find({'participant-phone':'08'}).count())

    @inlineCallbacks
    def test_run_action_feedback(self):
        self.initialize_properties()

        self.collections['participants'].save(self.mkobj_participant())

        context = Context()
        context.update({'request-id': '1'})

        self.worker.run_action(
            '06',
            FeedbackAction(**{'content': 'message'}),
            context,
            '1')
        messages = yield self.app_helper.get_dispatched_outbound()
        self.assertEqual(len(messages), 1)
        self.assertEqual(self.collections['history'].count(), 1)
        history = self.collections['history'].find_one()
        self.assertEqual(history['participant-session-id'], '1')
        self.assertEqual(history['participant-phone'], '06')

    @inlineCallbacks
    def test_run_action_feedback_simulated(self):
        self.initialize_properties()

        participant = self.mkobj_participant()
        participant['simulate'] = True
        self.collections['participants'].save(participant)

        context = Context()
        context.update({'request-id': '1'})

        self.worker.run_action(
            '06',
            FeedbackAction(**{'content': 'message'}),
            context,
            '1')
        messages = yield self.app_helper.get_dispatched_outbound()
        self.assertEqual(len(messages), 0)
        self.assertEqual(self.collections['history'].count(), 1)
        history = self.collections['history'].find_one()
        self.assertEqual(history['participant-session-id'], '1')
        self.assertEqual(history['participant-phone'], '06')

    @inlineCallbacks
    def test_run_action_sms_mo(self):
        self.initialize_properties()

        self.collections['participants'].save(self.mkobj_participant())

        context = Context()
        context.update({'request-id': '1'})

        self.worker.run_action(
            '06',
            SmsMoAction(**{'mo-content': 'test incoming MO message'}),
            context,
            '1')
        #messages = yield self.app_helper.get_dispatched_outbound()
        messages = yield self.app_helper.get_dispatched_inbound()
        #self.assertEqual(len(messages), 1)
        #self.assertEqual(self.collections['history'].count(), 1)
        #history = self.collections['history'].find_one()
        #self.assertEqual(history['participant-session-id'], '1')
        #self.assertEqual(history['participant-phone'], '06')

    @inlineCallbacks
    def test_run_action_enroll(self):
        self.initialize_properties()

        dNow = self.worker.get_local_time()
        self.collections['participants'].save(self.mkobj_participant(
            "08", last_optin_date=time_to_vusion_format(dNow)))        
        self.collections['dialogues'].save(
            self.mkobj_dialogue_question_offset_days())
        dBegin = self.worker.get_local_time()
     
        yield self.worker.run_action("08", EnrollingAction(**{'enroll': '01'}))
        participant = self.collections['participants'].find_one({'enrolled.dialogue-id': '01'})
        self.assertTrue(participant)
        self.assertEqual(1, self.collections['schedules'].count())
        self.assertTrue('date-time' in participant['enrolled'][0])
        dEnrolled = time_from_vusion_format(participant['enrolled'][0]['date-time'])
        self.assertTrue(dEnrolled - dBegin < timedelta(seconds=1))

        #Enrolling again should keep the old date
{'fraction_non_alphanumeric': 0.12771503040834056, 'fraction_numerical': 0.008340573414422242, 'mean_word_length': 2.9673713235294117, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4547635', 'n_tokens_mistral': 5050, 'n_tokens_neox': 4785, 'n_words': 774}