Exemplo n.º 1
0
    def test_drill_started_and_completed(self):
        user_id = self._make_user_and_get_id()
        event = DrillStarted(
            phone_number=self.phone_number,
            user_profile=UserProfile(True),
            drill=Drill(slug=get_all_drill_slugs()[0],
                        name="drill",
                        prompts=[]),
            first_prompt=self.prompt,
        )
        self.repo.update_user(self._make_batch([event]))
        drill_status = self.repo.get_drill_status(user_id,
                                                  get_all_drill_slugs()[0])
        self.assertEqual(event.created_time, drill_status.started_time)
        self.assertIsNone(drill_status.completed_time)

        event2 = DrillCompleted(
            phone_number=self.phone_number,
            user_profile=UserProfile(True),
            drill_instance_id=event.drill_instance_id,
        )
        self.repo.update_user(self._make_batch([event2]))
        drill_status = self.repo.get_drill_status(user_id,
                                                  get_all_drill_slugs()[0])
        self.assertEqual(event.created_time, drill_status.started_time)
        self.assertEqual(event2.created_time, drill_status.completed_time)
Exemplo n.º 2
0
 def test_idempotence(self):
     user_id = self._make_user_and_get_id()
     event = DrillStarted(
         phone_number=self.phone_number,
         user_profile=UserProfile(True),
         drill=self.drill,
         first_prompt=self.prompt,
     )
     batch1 = self._make_batch([event])
     self.repo.update_user(batch1)
     user = self.repo.get_user(user_id)
     self.assertEqual(event.created_time, user.last_interacted_time)
     event2 = FailedPrompt(
         phone_number=self.phone_number,
         user_profile=UserProfile(True),
         prompt=self.prompt,
         drill_instance_id=event.drill_instance_id,
         response="go",
         abandoned=True,
     )
     batch2 = self._make_batch([event2])
     batch2.seq = batch1.seq
     self.repo.update_user(batch2)
     user = self.repo.get_user(user_id)
     self.assertEqual(event.created_time, user.last_interacted_time)
Exemplo n.º 3
0
 def test_initiates_subsequent_drill(self):
     batch1 = DialogEventBatch(
         phone_number="123456789",
         seq="0",
         events=[
             NextDrillRequested(
                 phone_number="123456789",
                 user_profile=UserProfile(True),
                 code_validation_payload=CodeValidationPayload(valid=True),
             ),
             DrillStarted(
                 phone_number="123456789",
                 user_profile=UserProfile(True),
                 drill=self.drill,
                 first_prompt=self.drill.prompts[0],
             ),
         ],
     )
     batch2 = DialogEventBatch(
         phone_number="987654321",
         seq="1",
         events=[
             DrillStarted(
                 phone_number="987654321",
                 user_profile=UserProfile(True),
                 drill=self.drill,
                 first_prompt=self.drill.prompts[0],
             )
         ],
     )
     self.assertTrue(initiates_subsequent_drill(batch1))
     self.assertFalse(initiates_subsequent_drill(batch2))
Exemplo n.º 4
0
 def test_user_revalidated(self):
     user_id = self._make_user_and_get_id()
     for slug in get_all_drill_slugs():
         drill = copy(self.drill)
         drill.slug = slug
         event = DrillStarted(
             phone_number=self.phone_number,
             user_profile=UserProfile(True),
             drill=Drill(slug=slug, name="name", prompts=[]),
             first_prompt=self.prompt,
         )
         event2 = DrillCompleted(
             phone_number=self.phone_number,
             user_profile=UserProfile(True),
             drill_instance_id=event.drill_instance_id,
         )
         self.repo._mark_drill_started(user_id, event, self.repo.engine)
         self.repo._mark_drill_completed(event2, self.repo.engine)
         drill_status = self.repo.get_drill_status(user_id, slug)
         self.assertIsNotNone(drill_status.started_time)
         self.assertIsNotNone(drill_status.completed_time)
     self.repo.update_user(
         self._make_batch([
             UserValidated(
                 phone_number=self.phone_number,
                 user_profile=UserProfile(True),
                 code_validation_payload=CodeValidationPayload(valid=True),
             )
         ]))
     for slug in get_all_drill_slugs():
         drill_status = self.repo.get_drill_status(user_id, slug)
         self.assertIsNone(drill_status.drill_instance_id)
         self.assertIsNone(drill_status.started_time)
         self.assertIsNone(drill_status.completed_time)
Exemplo n.º 5
0
    def test_get_progress_empty(self):
        drill_progresses = list(
            self.repo.get_progress_for_users_who_need_drills(30))
        self.assertEqual(0, len(drill_progresses))

        # no started drills, so we won't receive anything
        self._make_user_and_get_id()
        drill_progresses = list(
            self.repo.get_progress_for_users_who_need_drills(30))
        self.assertEqual(0, len(drill_progresses))

        for slug in get_all_drill_slugs():
            event = DrillStarted(
                phone_number=self.phone_number,
                user_profile=UserProfile(True),
                drill=Drill(slug=slug, name="name", prompts=[]),
                first_prompt=self.prompt,
            )
            event2 = DrillCompleted(
                phone_number=self.phone_number,
                user_profile=UserProfile(True),
                drill_instance_id=event.drill_instance_id,
            )
            self.repo.update_user(self._make_batch([event, event2]))
        # all drills complete, so we won't receive anything
        drill_progresses = list(
            self.repo.get_progress_for_users_who_need_drills(30))
        self.assertEqual(0, len(drill_progresses))
Exemplo n.º 6
0
    def test_save_and_fetch(self):
        dialog_state = self.repo.fetch_dialog_state(self.phone_number)
        self.assertEqual(self.phone_number, dialog_state.phone_number)

        event1 = CompletedPrompt(
            phone_number=self.phone_number,
            user_profile=UserProfile(validated=True),
            prompt=Prompt(
                slug="one",
                messages=[
                    PromptMessage(text="one"),
                    PromptMessage(text="two")
                ],
            ),
            response="hi",
            drill_instance_id=uuid.uuid4(),
        )
        event2 = AdvancedToNextPrompt(
            phone_number=self.phone_number,
            user_profile=UserProfile(validated=True),
            prompt=Prompt(
                slug="two",
                messages=[
                    PromptMessage(text="three"),
                    PromptMessage(text="four")
                ],
            ),
            drill_instance_id=event1.drill_instance_id,
        )
        dialog_state = DialogState(
            phone_number=self.phone_number,
            seq="0",
            user_profile=UserProfile(validated=True, language="de"),
            drill_instance_id=event1.drill_instance_id,
        )
        batch = DialogEventBatch(phone_number=self.phone_number,
                                 events=[event1, event2],
                                 seq="216")

        self.repo.persist_dialog_state(batch, dialog_state)
        dialog_state2 = self.repo.fetch_dialog_state(self.phone_number)
        self.assertEqual(dialog_state.phone_number, dialog_state2.phone_number)
        self.assertEqual(dialog_state.user_profile.validated,
                         dialog_state2.user_profile.validated)
        self.assertEqual(dialog_state.user_profile.language,
                         dialog_state2.user_profile.language)

        batch_retrieved = self.repo.fetch_dialog_event_batch(
            self.phone_number, batch.batch_id)

        event1_retrieved = batch_retrieved.events[0]
        self.assertEqual(event1.response,
                         event1_retrieved.response)  # type: ignore

        event2_retrieved = batch_retrieved.events[1]
        self.assertEqual(event2.prompt.slug,
                         event2_retrieved.prompt.slug)  # type: ignore
Exemplo n.º 7
0
    def test_get_progress_multiple_users(self):
        user_id1 = self._make_user_and_get_id()
        user_id2 = self._make_user_and_get_id(phone_number="987654321")
        event = DrillStarted(
            phone_number=self.phone_number,
            user_profile=UserProfile(True),
            drill=Drill(slug=get_all_drill_slugs()[0], name="name",
                        prompts=[]),
            first_prompt=self.prompt,
            created_time=datetime.datetime.now(datetime.timezone.utc) -
            datetime.timedelta(minutes=32),
        )
        self.repo.update_user(self._make_batch([event]))

        event2 = DrillStarted(
            phone_number="987654321",
            user_profile=UserProfile(True),
            drill=Drill(slug=get_all_drill_slugs()[1], name="name",
                        prompts=[]),
            first_prompt=self.prompt,
            created_time=datetime.datetime.now(datetime.timezone.utc) -
            datetime.timedelta(minutes=32),
        )
        self.repo.update_user(self._make_batch([event2]))

        drill_progresses = list(
            self.repo.get_progress_for_users_who_need_drills(30))
        self.assertEqual(2, len(drill_progresses))
        if drill_progresses[0].user_id == user_id1:
            drill_progress1 = drill_progresses[0]
            drill_progress2 = drill_progresses[1]
        else:
            drill_progress1 = drill_progresses[1]
            drill_progress2 = drill_progresses[0]
        self.assertEqual(
            DrillProgress(
                phone_number=self.phone_number,
                user_id=user_id1,
                first_unstarted_drill_slug=get_all_drill_slugs()[1],
                first_incomplete_drill_slug=get_all_drill_slugs()[0],
            ),
            drill_progress1,
        )
        self.assertEqual(
            DrillProgress(
                phone_number="987654321",
                user_id=user_id2,
                first_unstarted_drill_slug=get_all_drill_slugs()[0],
                first_incomplete_drill_slug=get_all_drill_slugs()[0],
            ),
            drill_progress2,
        )
Exemplo n.º 8
0
    def test_create_or_update_user(self):
        batch = DialogEventBatch(
            phone_number=self.phone_number,
            seq=self._seq(),
            events=[
                DrillCompleted(
                    phone_number=self.phone_number,
                    user_profile=UserProfile(
                        True,
                        language="zh",
                        account_info={
                            "employer_id": Decimal(123),
                            "unit_id": Decimal(456)
                        },
                    ),
                    drill_instance_id=uuid.uuid4(),
                )
            ],
        )
        user_id = self.repo._create_or_update_user(batch, None,
                                                   self.repo.engine)
        user = self.repo.get_user(user_id)
        self.assertEqual(user_id, user.user_id)
        self.assertEqual({
            "employer_id": 123,
            "unit_id": 456
        }, user.profile["account_info"])
        self.assertEqual(True, user.profile["validated"])
        self.assertEqual("zh", user.profile["language"])
        self.assertIsNone(user.last_interacted_time)
        self.assertEqual(batch.seq, user.seq)

        batch2 = self._make_batch([
            DrillCompleted(
                phone_number=self.phone_number,
                user_profile=UserProfile(True,
                                         account_info={
                                             "foo": "bar",
                                             "one": "two"
                                         }),
                drill_instance_id=uuid.uuid4(),
            )
        ])

        self.repo._create_or_update_user(batch2, None, self.repo.engine)
        user = self.repo.get_user(user_id)
        self.assertEqual({
            "foo": "bar",
            "one": "two"
        }, user.profile["account_info"])
        self.assertEqual(batch2.seq, user.seq)
Exemplo n.º 9
0
 def test_user_revalidated(self):
     profile = UserProfile(validated=True, is_demo=True)
     dialog_state = DialogState(
         "123456789",
         "0",
         user_profile=profile,
         current_drill=DRILL,
         drill_instance_id=uuid.uuid4(),
         current_prompt_state=PromptState(slug=DRILL.prompts[0].slug,
                                          start_time=NOW),
     )
     event = UserValidated(
         phone_number="123456789",
         user_profile=profile,
         code_validation_payload=CodeValidationPayload(
             valid=True, is_demo=False, account_info={"foo": "bar"}),
     )
     event.apply_to(dialog_state)
     self.assertTrue(dialog_state.user_profile.validated)
     self.assertFalse(dialog_state.user_profile.is_demo)
     self.assertIsNone(dialog_state.current_drill)
     self.assertIsNone(dialog_state.current_prompt_state)
     self.assertIsNone(dialog_state.drill_instance_id)
     self.assertEqual({"foo": "bar"},
                      dialog_state.user_profile.account_info)
Exemplo n.º 10
0
 def test_user_validation_failed(self):
     profile = UserProfile(validated=False)
     dialog_state = DialogState("123456789", "0", user_profile=profile)
     event = UserValidationFailed(phone_number="123456789",
                                  user_profile=profile)
     event.apply_to(dialog_state)
     self.assertFalse(dialog_state.user_profile.validated)
Exemplo n.º 11
0
 def test_user_validated(self):
     profile = UserProfile(validated=False)
     dialog_state = DialogState(phone_number="123456789",
                                seq="0",
                                user_profile=profile)
     event = UserValidated(
         phone_number="123456789",
         user_profile=profile,
         code_validation_payload=CodeValidationPayload(
             valid=True,
             is_demo=False,
             account_info={
                 "employer_id": 1,
                 "unit_id": 1,
                 "employer_name": "employer_name",
                 "unit_name": "unit_name",
             },
         ),
     )
     event.apply_to(dialog_state)
     self.assertTrue(dialog_state.user_profile.validated)
     self.assertEqual(
         {
             "employer_id": 1,
             "unit_id": 1,
             "employer_name": "employer_name",
             "unit_name": "unit_name",
         },
         dialog_state.user_profile.account_info,
     )
Exemplo n.º 12
0
 def test_failed_and_not_abandoned(self):
     profile = UserProfile(validated=True)
     event = FailedPrompt(
         phone_number="123456789",
         user_profile=profile,
         prompt=DRILL.prompts[2],
         drill_instance_id=uuid.uuid4(),
         response="b",
         abandoned=False,
     )
     dialog_state = DialogState(
         "123456789",
         seq="0",
         user_profile=profile,
         current_drill=DRILL,
         drill_instance_id=event.drill_instance_id,
         current_prompt_state=PromptState(DRILL.prompts[2].slug,
                                          start_time=NOW),
     )
     event.apply_to(dialog_state)
     self.assertEqual(
         PromptState(
             slug=DRILL.prompts[2].slug,
             start_time=NOW,
             last_response_time=event.created_time,
             failures=1,
         ),
         dialog_state.current_prompt_state,
     )
Exemplo n.º 13
0
    def test_get_progress_for_users_one_user(self):
        user_id = self._make_user_and_get_id()
        event = DrillStarted(
            phone_number=self.phone_number,
            user_profile=UserProfile(True),
            drill=Drill(slug=get_all_drill_slugs()[0], name="name",
                        prompts=[]),
            first_prompt=self.prompt,
            created_time=datetime.datetime.now(datetime.timezone.utc) -
            datetime.timedelta(minutes=32),
        )
        self.repo.update_user(self._make_batch([event]))

        drill_progresses = list(
            self.repo.get_progress_for_users_who_need_drills(30))
        self.assertEqual(1, len(drill_progresses))
        self.assertEqual(
            DrillProgress(
                user_id=user_id,
                phone_number=self.phone_number,
                first_incomplete_drill_slug=get_all_drill_slugs()[0],
                first_unstarted_drill_slug=get_all_drill_slugs()[1],
            ),
            drill_progresses[0],
        )

        event2 = DrillCompleted(
            phone_number=self.phone_number,
            user_profile=UserProfile(True),
            drill_instance_id=event.drill_instance_id,
            created_time=datetime.datetime.now(datetime.timezone.utc) -
            datetime.timedelta(minutes=31),
        )
        self.repo.update_user(self._make_batch([event2]))
        drill_progresses = list(
            self.repo.get_progress_for_users_who_need_drills(30))
        self.assertEqual(1, len(drill_progresses))
        self.assertEqual(
            DrillProgress(
                user_id=user_id,
                phone_number=self.phone_number,
                first_incomplete_drill_slug=get_all_drill_slugs()[1],
                first_unstarted_drill_slug=get_all_drill_slugs()[1],
            ),
            drill_progresses[0],
        )
Exemplo n.º 14
0
 def test_unhandled_message_received(self):
     original = UnhandledMessageReceived(
         phone_number="123456789",
         user_profile=UserProfile(validated=True),
         message="blabla")
     serialized = original.dict()
     deserialized = event_from_dict(serialized)
     self._make_base_assertions(original, deserialized)
Exemplo n.º 15
0
 def test_menu_requested(self):
     original = MenuRequested(
         phone_number="123456789",
         user_profile=UserProfile(validated=True),
     )
     serialized = original.dict()
     deserialized = event_from_dict(serialized)
     self._make_base_assertions(original, deserialized)
Exemplo n.º 16
0
 def test_opted_out(self):
     original = OptedOut("123456789",
                         user_profile=UserProfile(True),
                         drill_instance_id=uuid.uuid4())
     serialized = original.to_dict()
     deserialized: OptedOut = event_from_dict(serialized)  # type: ignore
     self._make_base_assertions(original, deserialized)
     self.assertEqual(original.drill_instance_id,
                      deserialized.drill_instance_id)
Exemplo n.º 17
0
 def test_send_adhoc_message(self):
     original = AdHocMessageSent(
         phone_number="123456789",
         user_profile=UserProfile(validated=True),
         sms=SMS(body="foobar"),
     )
     serialized = original.dict()
     deserialized = event_from_dict(serialized)
     self._make_base_assertions(original, deserialized)
Exemplo n.º 18
0
 def test_user_validated(self):
     original = UserValidated(
         "123456789",
         user_profile=UserProfile(True),
         code_validation_payload=CodeValidationPayload(valid=True,
                                                       is_demo=True),
     )
     serialized = original.to_dict()
     deserialized = event_from_dict(serialized)
     self._make_base_assertions(original, deserialized)
Exemplo n.º 19
0
 def test_drill_completed(self):
     original = DrillCompleted(phone_number="12345678",
                               user_profile=UserProfile(True),
                               drill_instance_id=uuid.uuid4())
     serialized = original.to_dict()
     deserialized: DrillCompleted = event_from_dict(
         serialized)  # type: ignore
     self._make_base_assertions(original, deserialized)
     self.assertEqual(original.drill_instance_id,
                      deserialized.drill_instance_id)
Exemplo n.º 20
0
    def test_next_drill_requested(self):
        profile = UserProfile(validated=True, opted_out=True)
        event = NextDrillRequested("123456789",
                                   user_profile=profile,
                                   drill_instance_id=uuid.uuid4())
        dialog_state = DialogState("123456789", seq="0", user_profile=profile)

        self.assertTrue(profile.opted_out)
        event.apply_to(dialog_state)
        self.assertFalse(profile.opted_out)
Exemplo n.º 21
0
 def test_opted_out_no_drill(self):
     user_id = self._make_user_and_get_id()
     event = OptedOut(phone_number=self.phone_number,
                      user_profile=UserProfile(True),
                      drill_instance_id=None)
     self.repo.update_user(self._make_batch([event]))
     drill_status = self.repo.get_drill_status(user_id,
                                               get_all_drill_slugs()[0])
     self.assertIsNone(drill_status.started_time)
     self.assertIsNone(drill_status.completed_time)
Exemplo n.º 22
0
 def fetch_dialog_state(self, phone_number: str) -> DialogState:
     if phone_number in self.repo:
         state = DialogStateSchema().loads(self.repo[phone_number])
         return state
     else:
         return DialogState(
             phone_number=phone_number,
             seq="0",
             user_profile=UserProfile(False, language=self.lang),
         )
Exemplo n.º 23
0
 def test_completed_and_stored(self):
     profile = UserProfile(validated=True)
     event = CompletedPrompt(
         "123456789",
         user_profile=profile,
         prompt=DRILL.prompts[1],
         drill_instance_id=uuid.uuid4(),
         response="7",
     )
     dialog_state = DialogState(
         "123456789",
         "0",
         user_profile=profile,
         current_drill=DRILL,
         current_prompt_state=PromptState(DRILL.prompts[0].slug, NOW),
     )
     event.apply_to(dialog_state)
     self.assertEqual(UserProfile(validated=True, self_rating_1="7"),
                      dialog_state.user_profile)
     self.assertIsNone(dialog_state.current_prompt_state)
Exemplo n.º 24
0
 def test_opted_out_during_drill(self):
     self.repo._save_drill_instance(self.drill_instance)
     event = OptedOut(
         phone_number=self.phone_number,
         user_profile=UserProfile(True),
         drill_instance_id=self.drill_instance.drill_instance_id,
     )
     self.repo.update_user(self._make_batch([event]))
     retrieved = self.repo.get_drill_instance(
         self.drill_instance.drill_instance_id)
     self.assertFalse(retrieved.is_valid)
Exemplo n.º 25
0
 def test_last_interacted(self):
     user_id = self._make_user_and_get_id()
     event = DrillStarted(
         phone_number=self.phone_number,
         user_profile=UserProfile(True),
         drill=self.drill,
         first_prompt=self.prompt,
     )
     self.repo.update_user(self._make_batch([event]))
     user = self.repo.get_user(user_id)
     self.assertEqual(event.created_time, user.last_interacted_time)
     event2 = CompletedPrompt(
         phone_number=self.phone_number,
         user_profile=UserProfile(True),
         prompt=self.prompt,
         drill_instance_id=event.drill_instance_id,
         response="go",
     )
     self.repo.update_user(self._make_batch([event2]))
     user = self.repo.get_user(user_id)
     self.assertEqual(event2.created_time, user.last_interacted_time)
    def setUp(self):
        self.phone = "+15554238324"
        self.validated_user_profile = UserProfile(
            validated=True,
            language="en",
            name="Mario",
            is_demo=False,
            account_info=AccountInfo(
                employer_id=1,
                employer_name="Tacombi",
                unit_id=1,
                unit_name="unit name",
            ),
        )
        self.non_validated_user_profile = UserProfile(validated=False,
                                                      language="en",
                                                      name="Luigi",
                                                      is_demo=False)

        self.drill = Drill(
            name="Test Drill",
            slug="test-drill",
            prompts=[
                Prompt(slug="ignore-response-1",
                       messages=[PromptMessage(text="Hello")]),
                Prompt(
                    slug="graded-response-1",
                    messages=[
                        PromptMessage(text="Intro!"),
                        PromptMessage(text="Question 1"),
                    ],
                    correct_response="a) Philadelphia",
                ),
                Prompt(
                    slug="graded-response-2",
                    messages=[PromptMessage(text="Question 2")],
                    correct_response="b",
                ),
            ],
        )
Exemplo n.º 27
0
 def _make_user_and_get_id(self, **overrides) -> uuid.UUID:
     return self.repo._create_or_update_user(
         self._make_batch([
             UserValidated(
                 phone_number=overrides.get("phone_number",
                                            self.phone_number),
                 user_profile=UserProfile(True),
                 code_validation_payload=CodeValidationPayload(valid=True),
             )
         ]),
         None,
         self.repo.engine,
     )
Exemplo n.º 28
0
 def test_language_change_drill_requested(self):
     original = LanguageChangeDrillRequested(
         phone_number="123456789",
         user_profile=UserProfile(validated=True),
         abandoned_drill_instance_id="11111111-1111-1111-1111-111111111111",
     )
     serialized = original.dict()
     deserialized = event_from_dict(serialized)
     self._make_base_assertions(original, deserialized)
     self.assertEqual(
         deserialized.abandoned_drill_instance_id,
         uuid.UUID("11111111-1111-1111-1111-111111111111"),
     )
Exemplo n.º 29
0
    def test_opted_out_no_drill(self):
        profile = UserProfile(validated=True)
        event = OptedOut("123456789",
                         user_profile=profile,
                         drill_instance_id=None)
        dialog_state = DialogState("123456789", seq="0", user_profile=profile)

        self.assertFalse(profile.opted_out)
        event.apply_to(dialog_state)
        self.assertTrue(profile.opted_out)
        self.assertIsNone(dialog_state.drill_instance_id)
        self.assertIsNone(dialog_state.current_prompt_state)
        self.assertIsNone(dialog_state.current_drill)
Exemplo n.º 30
0
 def test_user_validated(self):
     profile = UserProfile(validated=False)
     dialog_state = DialogState("123456789", "0", user_profile=profile)
     event = UserValidated(
         phone_number="123456789",
         user_profile=profile,
         code_validation_payload=CodeValidationPayload(
             valid=True, is_demo=False, account_info={"foo": "bar"}),
     )
     event.apply_to(dialog_state)
     self.assertTrue(dialog_state.user_profile.validated)
     self.assertEqual({"foo": "bar"},
                      dialog_state.user_profile.account_info)