def test_compute_nps_report(self, unused_mock_sentry_logging, mock_post): """Test computing the NPS report on multiple user feedback.""" self._db.user.insert_many([ { '_id': mongomock.ObjectId('123400000012340000001234'), 'registeredAt': '2017-11-01T12:00:00Z', 'netPromoterScoreSurveyResponse': { 'respondedAt': '2017-11-01T16:00:00Z', 'score': 0, 'generalFeedbackComment': 'The app was blocked for me :-(', }, }, { 'registeredAt': '2017-11-01T12:00:00Z', 'netPromoterScoreSurveyResponse': { 'respondedAt': '2017-11-01T16:00:00Z', 'score': 9, }, }, { 'registeredAt': '2017-11-01T12:00:00Z', 'netPromoterScoreSurveyResponse': { 'respondedAt': '2017-11-01T16:00:00Z', 'score': 6, }, }, { '_id': mongomock.ObjectId('000056780000005678000000'), 'registeredAt': '2017-11-01T12:00:00Z', 'netPromoterScoreSurveyResponse': { 'respondedAt': '2017-11-01T16:00:00Z', 'score': 9, 'generalFeedbackComment': 'You rock!', }, }, # User registered and answered the NPS after the to_date. { 'registeredAt': '2017-11-11T12:00:00Z', 'netPromoterScoreSurveyResponse': { 'respondedAt': '2017-11-11T16:00:00Z', 'score': 0, }, }, ]) feedback_report.main([ 'nps', '--from', '2017-10-30', '--to', '2017-11-07', '--no-dry-run' ], io.StringIO()) slack_json = mock_post.call_args[1]['json'] self.assertEqual( '4 users answered the NPS survey for a global NPS of *25.0%*\n' '*9*: 2 users\n' '*6*: 1 user\n' '*0*: 1 user\n' 'And here are the individual comments:\n' '[Score: 9] ObjectId("000056780000005678000000")\n' '> You rock!\n' '[Score: 0] ObjectId("123400000012340000001234")\n' '> The app was blocked for me :-(', slack_json['attachments'][0]['text'])
def test_delete_user_token(self): """Delete a user without its ID but with an auth token.""" user_info = { 'profile': { 'city': { 'name': 'foobar' }, 'name': 'Albert', 'year_of_birth': 1973 }, 'projects': [{}] } user_id = self.create_user(data=user_info, email='*****@*****.**') token = server.auth.create_token('*****@*****.**', role='unsubscribe') response = self.app.delete( '/api/user', data='{"profile": {"email": "*****@*****.**"}}', headers={'Authorization': 'Bearer {}'.format(token)}) self.assertEqual(200, response.status_code) auth_object = self._user_db.user_auth.find_one( {'_id': mongomock.ObjectId(user_id)}) self.assertFalse(auth_object) user_data = self._user_db.user.find_one( {'_id': mongomock.ObjectId(user_id)}) self.assertEqual('REDACTED', user_data['profile']['email']) self.assertEqual('REDACTED', user_data['profile']['name']) self.assertEqual(1973, user_data['profile']['yearOfBirth']) self.assertIn('deletedAt', user_data) # Pop _id field which is not JSON serializable user_data.pop('_id') self.assertNotIn('*****@*****.**', json.dumps(user_data))
def test_registered_from_days_ago( self, mock_requests: requests_mock.Mocker) -> None: """Test update_users_client_metrics.""" mock_db = mongomock.MongoClient().test mock_db.user.insert_many([ { '_id': mongomock.ObjectId('7ed900dbfbebdee97f9e2332'), 'registeredAt': '2017-11-17T10:57:12Z', }, # User registered just "today" (the day the script is run). { '_id': mongomock.ObjectId('7ed900dbfbebd00000000004'), 'registeredAt': '2017-11-19T10:57:12Z', }, ]) patcher = mock.patch(sync_amplitude.__name__ + '._DB', new=mock_db) patcher.start() self.addCleanup(patcher.stop) mock_requests.get( 'https://amplitude.com/api/2/usersearch?user=7ed900dbfbebdee97f9e2332', json={'matches': [{ 'amplitude_id': 42 }]}) mock_requests.get( 'https://amplitude.com/api/2/useractivity?user=42', json={ 'events': [ { 'event_time': '2017-10-24 10:41:00.412000', 'event_properties': { 'Mobile Version': True, }, }, # Last event of the session: 25 min, 5.1 sec later. { 'event_time': '2017-10-24 11:06:05.512000' }, ] }) sync_amplitude.main([ '--registered-from', '2017-11-14', '--disable-sentry', '--no-dry-run' ]) user = user_pb2.User() proto.parse_from_mongo( mock_db.user.find_one({ '_id': mongomock.ObjectId('7ed900dbfbebdee97f9e2332'), }), user) self.assertEqual('42', user.client_metrics.amplitude_id) self.assertEqual(25 * 60 + 5, user.client_metrics.first_session_duration_seconds) self.assertEqual(project_pb2.TRUE, user.client_metrics.is_first_session_mobile)
def setUp(self) -> None: super().setUp() self._user_db.feedbacks.insert_many([ # 2022-02-01 { '_id': mongomock.ObjectId('61f878000000000000000000'), 'userId': 'the first' }, # 2022-02-02 { '_id': mongomock.ObjectId('61f9c9800000000000000000'), 'userId': 'someone' }, ])
def test_favor_tips_never_given(self): """Favor tips that were never sent.""" self.database.advice_modules.insert_one({ 'adviceId': 'my-advice', 'tipTemplateIds': ['tip-a', 'tip-b'], }) self.database.tip_templates.insert_many([ { '_id': 'tip-a', 'actionTemplateId': 'tip-a', 'title': 'Tip already sent', 'isReadyForEmail': True, }, { '_id': 'tip-b', 'actionTemplateId': 'tip-b', 'title': 'Tip never sent', 'isReadyForEmail': True, }, ]) user_id = mongomock.ObjectId() self.database.email_history.update_one( {'_id': user_id}, {'$set': {'tips.tip-a': now.get().isoformat() + 'Z'}}, upsert=True, ) tips = advisor.select_tips_for_email( user_pb2.User(user_id=str(user_id)), project_pb2.Project(), advisor_pb2.AdviceModule(advice_id='my-advice'), self.database, num_tips=1) self.assertEqual(['Tip never sent'], sorted(t.title for t in tips))
def test_main(self, mock_post: mock.MagicMock) -> None: """Overall test.""" _db = pymongo.MongoClient('mongodb://my-db/db').db _db.user.drop() _db.user.insert_one({ '_id': mongomock.ObjectId('5daf2298484ae6c93351b822'), 'profile': { 'name': 'Pascal', 'lastName': 'Corpet', 'email': '*****@*****.**', 'locale': 'en', }, 'registeredAt': datetime.datetime(2018, 1, 22, 10, 0, 0).isoformat() + 'Z', 'projects': [{ 'title': 'Project Title', }], }) mail_nps.main(self._now, '1') sent_messages = mailjetmock.get_all_sent_messages() self.assertEqual(['*****@*****.**'], [m.recipient['Email'] for m in sent_messages]) self.assertEqual(100819, sent_messages[0].properties['TemplateID']) template_vars = sent_messages[0].properties['Variables'] nps_form_urlstring = template_vars.pop('npsFormUrl') self.assertEqual( { 'baseUrl': 'http://localhost:3000', 'firstName': 'Pascal', }, template_vars) nps_form_url = parse.urlparse(nps_form_urlstring) self.assertEqual( 'http://localhost:3000/api/nps', parse.urlunparse(nps_form_url[:4] + ('', ) + nps_form_url[5:])) nps_form_args = parse.parse_qs(nps_form_url.query) self.assertEqual({'user', 'token', 'redirect'}, nps_form_args.keys()) self.assertEqual(['5daf2298484ae6c93351b822'], nps_form_args['user']) auth.check_token('5daf2298484ae6c93351b822', nps_form_args['token'][0], role='nps') self.assertEqual(['http://localhost:3000/retours?hl=en'], nps_form_args['redirect']) mock_post.assert_called_once_with( 'https://slack.example.com/webhook', json={ 'text': "Report for NPS blast: I've sent 1 emails (with 0 errors)." }, ) modified_user = user_pb2.User() proto.parse_from_mongo(_db.user.find_one(), modified_user) self.assertEqual( [sent_messages[0].message_id], [m.mailjet_message_id for m in modified_user.emails_sent]) self.assertEqual('nps', modified_user.emails_sent[0].campaign_id)
def user_info_from_db(self, user_id: str) -> Dict[str, Any]: """Get user's info directly from DB without calling any endpoint.""" user_info = self._user_db.user.find_one( {'_id': mongomock.ObjectId(user_id)}) self.assertIn('_server', user_info) return {k: v for k, v in user_info.items() if not k.startswith('_')}
def test_signal(self, mock_mail, mock_report_mail): """Test that the batch send fails gracefully on SIGTERM.""" mock_mail.send_template.return_value.status_code = 200 mock_mail.send_template.return_value.json.return_value = { 'Sent': [{ 'MessageID': 123456, }] } mock_report_mail.send_template_to_admins.return_value.status_code = 200 self._db.user.insert_many([ dict(_USER_PENDING_NPS_DICT, _id=mongomock.ObjectId('580f4a4271cd4a0007672a%dd' % i)) for i in range(10) ]) users = list(self._db.user.find({})) db_user = mock.MagicMock() db_user.find.return_value = _SigtermAfterNItems(users, 3) mail_nps.main(db_user, 'http://localhost:3000', self._now, '1') self.assertEqual(4, mock_mail.send_template.call_count) self.assertEqual(4, db_user.update_one.call_count) self.assertTrue(mock_report_mail.send_template_to_admins.called)
def test_any_advice_in_the_week(self): """Any advice in the middle of the week.""" user = user_pb2.User( user_id=str(mongomock.ObjectId()), features_enabled=user_pb2.Features(advisor=user_pb2.ACTIVE), projects=[project_pb2.Project(advices=[ project_pb2.Advice( advice_id='priority-advice', num_stars=3, score=8, ), project_pb2.Advice( advice_id='easy-advice', num_stars=1, score=2, ), ])], ) advice_given = set() for unused_index in range(101): advice = advisor.select_advice_for_email(user, user_pb2.WEDNESDAY, self.database) self.assertTrue(advice) self.assertIn(advice.advice_id, {'easy-advice', 'priority-advice'}) advice_given.add(advice.advice_id) if len(advice_given) > 2: break # This could fail with a probability of .8^100 ~= 2e-10. self.assertEqual({'easy-advice', 'priority-advice'}, advice_given)
def test_missing_sentry(self, unused_mock_requests: requests_mock.Mocker, mock_logging: mock.MagicMock) -> None: """Missing sentry env var.""" mock_db = mongomock.MongoClient().test mock_db.user.insert_one({ '_id': mongomock.ObjectId('7ed900dbfbebdee97f9e2332'), 'registeredAt': '2017-11-17T10:57:12Z', }) patcher = mock.patch(sync_amplitude.__name__ + '._DB', new=mock_db) patcher.start() self.addCleanup(patcher.stop) sync_amplitude.main([ '--registered-from', '2017-11-14', '--registered-to', '2017-11-18', '--no-dry-run' ]) user = user_pb2.User() proto.parse_from_mongo(mock_db.user.find_one({}), user) self.assertFalse(user.client_metrics.amplitude_id) mock_logging.assert_called_once()
def test_filter_after(self, mock_verify_oauth2_token: mock.MagicMock) -> None: """Test filtering only recent feedback.""" mock_verify_oauth2_token.return_value = { 'iss': 'accounts.google.com', 'email': '*****@*****.**', 'sub': '12345', } self._user_db.feedbacks.insert_many([ # 2021-01-01 { '_id': mongomock.ObjectId('5fee66000000000000000000'), 'userId': 'very old feedback' }, { '_id': mongomock.ObjectId.from_datetime(datetime.datetime(2021, 1, 2)), 'userId': 'very old feedback', }, ]) response = self.app.get( '/api/eval/feedback/export?token=blabla&data=%7B"ater"%3A"2022-02-01T15:00:00Z"%7D' ) self.assertNotIn('very old feedback', response.get_data(as_text=True))
def test_signal(self, mock_select_advice, unused_mock_select_tips, mock_mail): """Test that the batch send fails gracefully on SIGTERM.""" mock_select_advice.return_value = project_pb2.Advice( advice_id='advice-to-send', num_stars=2, ) mock_mail.send_template.return_value.status_code = 200 mock_mail.send_template_to_admins.return_value.status_code = 200 mock_mail.count_sent_to.return_value = { 'DeliveredCount': 0, 'OpenedCount': 0 } self._db.user.insert_many([ dict(_USER_READY_FOR_EMAIL, _id=mongomock.ObjectId('580f4a4271cd4a0007672a%dd' % i)) for i in range(10) ]) users = list(self._db.user.find({})) db_user = mock.MagicMock() db_user.find.return_value = _SigtermAfterNItems(users, 3) self._db.user = db_user mail_advice.main(self._db, 'http://localhost:3000', self._now) self.assertEqual(4, mock_mail.send_template.call_count) self.assertEqual(4, db_user.update_one.call_count) self.assertTrue(mock_mail.send_template_to_admins.called)
def create_user_that(self, predicate, num_tries=50, *args, **kwargs): """Creates a user that passes a predicate. Args: predicate: the predicate on the JSON-like dict to pass. num_tries: the number of creation attempt that we should try. args, kwargs: the parameters to send to the create_user method on each attempt. Returns: a user ID. Raises: AssertionError: if we could not create a user that passes the predicate in the given number of tries. """ for unused_ in range(num_tries): user_id = self.create_user(*args, **kwargs) user_data = self._db.user.find_one( {'_id': mongomock.ObjectId(user_id)}) try: if predicate(user_data): return user_id except KeyError: pass self.fail('Could not create a user that matches the predicate' ) # pragma: no cover
def _assert_user_receives_campaign(self, mock_mail=None, should_be_sent=True): json_user = json_format.MessageToDict(self.user) json_user['_id'] = mongomock.ObjectId(json_user.pop('userId')) self._user_database.user.insert_one(json_user) mock_mail().status_code = 200 mock_mail().json.return_value = { 'Sent': [{ 'MessageID': 18014679230180635 }] } mock_mail.reset_mock() year = self.user.registered_at.ToDatetime().year mail_blast.main([ self._campaign_id, 'send', '--disable-sentry', '--registered-from', str(year), '--registered-to', str(year + 1), ]) if not should_be_sent: self.assertFalse(mock_mail.called) return mock_mail.assert_called_once() self._variables = mock_mail.call_args[0][2]
def test_unknown_user(self, mock_requests: requests_mock.Mocker) -> None: """Test update_users_client_metrics with an unknown user.""" mock_db = mongomock.MongoClient().test mock_db.user.insert_one({ '_id': mongomock.ObjectId('7ed900dbfbebdee97f9e2332'), 'registeredAt': '2017-11-17T10:57:12Z', }) patcher = mock.patch(sync_amplitude.__name__ + '._DB', new=mock_db) patcher.start() self.addCleanup(patcher.stop) mock_requests.get( 'https://amplitude.com/api/2/usersearch?user=7ed900dbfbebdee97f9e2332', json={'matches': []}) sync_amplitude.main([ '--registered-from', '2017-11-14', '--registered-to', '2017-11-18', '--disable-sentry', '--no-dry-run' ]) user = user_pb2.User() proto.parse_from_mongo(mock_db.user.find_one({}), user) self.assertEqual('Not Found', user.client_metrics.amplitude_id)
def test_three_tips(self): """Only three tips.""" self.database.advice_modules.insert_one({ 'adviceId': 'has-3-tips', 'tipTemplateIds': ['tip-a', 'tip-b', 'tip-c'], }) self.database.tip_templates.insert_many([ { '_id': 'tip-a', 'actionTemplateId': 'tip-a', 'emailTitle': 'First tip', 'isReadyForEmail': True, }, { '_id': 'tip-b', 'actionTemplateId': 'tip-b', 'emailTitle': 'Second tip', 'isReadyForEmail': True, }, { '_id': 'tip-c', 'actionTemplateId': 'tip-c', 'emailTitle': 'Third tip', 'isReadyForEmail': True, }, ]) tips = advisor.select_tips_for_email( user_pb2.User(user_id=str(mongomock.ObjectId())), project_pb2.Project(), advisor_pb2.AdviceModule(advice_id='has-3-tips'), self.database) self.assertEqual( ['First tip', 'Second tip', 'Third tip'], sorted(t.title for t in tips))
def test_too_many_requests(self, mock_requests): """Test too many requests.""" mock_db = mongomock.MongoClient().test mock_db.user.insert_one({ '_id': mongomock.ObjectId('7ed900dbfbebdee97f9e2332'), 'registeredAt': '2017-11-17T10:57:12Z', }) patcher = mock.patch(sync_amplitude.__name__ + '._DB', new=mock_db) patcher.start() self.addCleanup(patcher.stop) mock_requests.get( 'https://amplitude.com/api/2/usersearch?user=7ed900dbfbebdee97f9e2332', status_code=429, reason='429 Client Error: Too many requests for url', ) with self.assertRaises(sync_amplitude.TooManyRequestsException): sync_amplitude.main([ '--registered-from', '2017-11-14', '--registered-to', '2017-11-18', '--disable-sentry', '--no-dry-run' ])
def test_compute_nps_report_no_comments(self, unused_mock_sentry_logging, mock_post): """Test computing the NPS report on multiple user feedback.""" self._db.user.insert_many([ { '_id': mongomock.ObjectId('123400000012340000001234'), 'registeredAt': '2017-11-01T12:00:00Z', 'netPromoterScoreSurveyResponse': { 'respondedAt': '2017-11-01T16:00:00Z', 'score': 0, }, }, { 'registeredAt': '2017-11-01T12:00:00Z', 'netPromoterScoreSurveyResponse': { 'respondedAt': '2017-11-01T16:00:00Z', 'score': 9, }, }, { 'registeredAt': '2017-11-01T12:00:00Z', 'netPromoterScoreSurveyResponse': { 'respondedAt': '2017-11-01T16:00:00Z', 'score': 6, }, }, { '_id': mongomock.ObjectId('000056780000005678000000'), 'registeredAt': '2017-11-01T12:00:00Z', 'netPromoterScoreSurveyResponse': { 'respondedAt': '2017-11-01T16:00:00Z', 'score': 9, }, }, ]) feedback_report.main([ 'nps', '--from', '2017-10-30', '--to', '2017-11-07', '--no-dry-run' ], io.StringIO()) slack_json = mock_post.call_args[1]['json'] self.assertEqual( '4 users answered the NPS survey for a global NPS of *25.0%*\n' '*9*: 2 users\n' '*6*: 1 user\n' '*0*: 1 user\n' 'There are no individual comments.', slack_json['attachments'][0]['text'])
def test_not_in_advisor(self): """User does not use the advisor yet.""" user_not_in_advisor = user_pb2.User( user_id=str(mongomock.ObjectId()), projects=[project_pb2.Project()], ) self.assertFalse(advisor.select_advice_for_email( user_not_in_advisor, user_pb2.TUESDAY, self.database))
def test_long_continuous_session( self, mock_requests: requests_mock.Mocker) -> None: """Test update_users_client_metrics with a user using Bob continuously for an hour.""" mock_db = mongomock.MongoClient().test mock_db.user.insert_one({ '_id': mongomock.ObjectId('7ed900dbfbebdee97f9e2332'), 'registeredAt': '2017-11-17T10:57:12Z', }) patcher = mock.patch(sync_amplitude.__name__ + '._DB', new=mock_db) patcher.start() self.addCleanup(patcher.stop) mock_requests.get( 'https://amplitude.com/api/2/usersearch?user=7ed900dbfbebdee97f9e2332', json={'matches': [{ 'amplitude_id': 42 }]}) mock_requests.get('https://amplitude.com/api/2/useractivity?user=42', json={ 'events': [ { 'event_time': '2017-10-24 10:40:00' }, { 'event_time': '2017-10-24 10:45:08' }, { 'event_time': '2017-10-24 11:06:05' }, { 'event_time': '2017-10-24 11:26:05' }, { 'event_time': '2017-10-24 11:46:05' }, { 'event_time': '2017-10-24 12:05:05' }, ] }) sync_amplitude.main([ '--registered-from', '2017-11-14', '--registered-to', '2017-11-18', '--disable-sentry', '--no-dry-run' ]) user = user_pb2.User() proto.parse_from_mongo(mock_db.user.find_one({}), user) self.assertEqual('42', user.client_metrics.amplitude_id) self.assertEqual(85 * 60 + 5, user.client_metrics.first_session_duration_seconds) self.assertEqual(project_pb2.FALSE, user.client_metrics.is_first_session_mobile)
def test_update_users_client_metrics( self, mock_requests: requests_mock.Mocker) -> None: """Test update_users_client_metrics.""" mock_db = mongomock.MongoClient().test mock_db.user.insert_one({ '_id': mongomock.ObjectId('7ed900dbfbebdee97f9e2332'), 'registeredAt': '2017-11-17T10:57:12Z', }) patcher = mock.patch(sync_amplitude.__name__ + '._DB', new=mock_db) patcher.start() self.addCleanup(patcher.stop) mock_requests.get( 'https://amplitude.com/api/2/usersearch?user=7ed900dbfbebdee97f9e2332', json={'matches': [{ 'amplitude_id': 42 }]}) mock_requests.get( 'https://amplitude.com/api/2/useractivity?user=42', json={ 'events': [ { 'event_time': '2017-10-24 10:41:08.396000' }, # Event out of order, this one is actually the first of the session. { 'event_time': '2017-10-24 10:41:00.412000' }, # Last event of the session: 25 min, 5.1 sec later. { 'event_time': '2017-10-24 11:06:05.512000' }, # Event really later: next session. { 'event_time': '2017-10-24 13:06:05' }, ] }) sync_amplitude.main([ '--registered-from', '2017-11-14', '--registered-to', '2017-11-18', '--disable-sentry', '--no-dry-run' ]) user = user_pb2.User() proto.parse_from_mongo(mock_db.user.find_one({}), user) self.assertEqual('42', user.client_metrics.amplitude_id) self.assertEqual(25 * 60 + 5, user.client_metrics.first_session_duration_seconds) self.assertEqual(project_pb2.FALSE, user.client_metrics.is_first_session_mobile)
def test_no_tips(self): """No tips.""" self.database.advice_modules.insert_one({ 'adviceId': 'has-no-tips', }) tips = advisor.select_tips_for_email( user_pb2.User(user_id=str(mongomock.ObjectId())), project_pb2.Project(), advisor_pb2.AdviceModule(advice_id='has-no-tips'), self.database) self.assertFalse(tips)
def test_one_advice_module_only(self): """Only one advice module was recommended.""" user = user_pb2.User( user_id=str(mongomock.ObjectId()), features_enabled=user_pb2.Features(advisor=user_pb2.ACTIVE), projects=[project_pb2.Project(advices=[project_pb2.Advice( advice_id='only-advice')])], ) advice = advisor.select_advice_for_email(user, user_pb2.TUESDAY, self.database) self.assertTrue(advice) self.assertEqual('only-advice', advice.advice_id)
def _assert_user_receives_campaign( self, should_be_sent: bool = True, blast_from: Optional[str] = None, blast_to: Optional[str] = None, extra_args: Optional[list[str]] = None) -> None: json_user = json_format.MessageToDict(self.user) json_user['_id'] = mongomock.ObjectId(json_user.pop('userId')) self._user_database.user.insert_one(json_user) year = self.user.registered_at.ToDatetime().year if self.now: now_patcher = nowmock.patch(new=mock.MagicMock( return_value=self.now)) now_patcher.start() self.addCleanup(now_patcher.stop) mail_blast.main([ self.campaign_id, 'send', '--disable-sentry', '--registered-from', blast_from or str(year), '--registered-to', blast_to or str(year + 1), '--log-reason-on-error', ] + (extra_args or [])) all_sent_messages = mailjetmock.get_all_sent_messages() if not should_be_sent: self.assertFalse(all_sent_messages) return self.assertEqual(1, len(all_sent_messages), msg=all_sent_messages) self.assertEqual(self.campaign_id, all_sent_messages[0].properties['CustomCampaign']) self._variables = all_sent_messages[0].properties['Variables'] self._from = all_sent_messages[0].properties['From'] self.assertEqual(self._from['Name'], self._variables.pop('senderName')) # Test that variables used in the template are populated. template_id = str(all_sent_messages[0].properties['TemplateID']) template_path = campaign.get_campaign_folder( typing.cast(mailjet_templates.Id, self.campaign_id)) self.assertTrue(template_path, msg=f'No template for campaign "{self.campaign_id}"') assert template_path vars_filename = os.path.join(template_path, 'vars-example.json') with open(vars_filename, 'r', encoding='utf-8') as vars_file: template_vars = json.load(vars_file).keys() for template_var in template_vars: self.assertIn( template_var, self._variables, msg=f'Template error for campaign {self.campaign_id}, see ' f'https://app.mailjet.com/template/{template_id}/build')
def test_delete_user(self): """Test deleting a user and all their data.""" user_info = { 'profile': { 'city': { 'name': 'foobar' }, 'name': 'Albert', 'year_of_birth': 1973 }, 'projects': [{}], 'emailsSent': [{ 'mailjetMessageId': 1234 }], } user_id, auth_token = self.create_user_with_token(data=user_info, email='*****@*****.**') response = self.app.delete( '/api/user', data='{{"userId": "{}", "profile": {{"email": "*****@*****.**"}}}}'. format(user_id), headers={'Authorization': 'Bearer ' + auth_token}) self.assertEqual(200, response.status_code) auth_object = self._user_db.user_auth.find_one( {'_id': mongomock.ObjectId(user_id)}) self.assertFalse(auth_object) user_data = self._user_db.user.find_one( {'_id': mongomock.ObjectId(user_id)}) self.assertEqual('REDACTED', user_data['profile']['email']) self.assertEqual('REDACTED', user_data['profile']['name']) self.assertEqual(1973, user_data['profile']['yearOfBirth']) self.assertIn('deletedAt', user_data) self.assertEqual([{}], user_data.get('emailsSent')) # Pop _id field which is not JSON serializable user_data.pop('_id') self.assertNotIn('*****@*****.**', json.dumps(user_data))
def test_different_advice_during_the_week(self, mock_now): """Different advice during the week.""" user_id = mongomock.ObjectId() user = user_pb2.User( user_id=str(user_id), features_enabled=user_pb2.Features(advisor=user_pb2.ACTIVE), projects=[project_pb2.Project(advices=[ project_pb2.Advice( advice_id='priority-advice', num_stars=3, score=8, ), project_pb2.Advice( advice_id='other-advice', num_stars=2, score=9, ), project_pb2.Advice( advice_id='easy-advice', num_stars=1, score=2, ), ])], ) advice_given = set() mock_now.return_value = datetime.datetime(2017, 4, 3, 13, 00) advice = advisor.select_advice_for_email(user, user_pb2.MONDAY, self.database) advice_given.add(advice.advice_id) self.database.email_history.update_one( {'_id': user_id}, {'$set': {'advice_modules.%s' % advice.advice_id: mock_now().isoformat() + 'Z'}}, upsert=True, ) mock_now.return_value = datetime.datetime(2017, 4, 5, 13, 00) advice = advisor.select_advice_for_email(user, user_pb2.WEDNESDAY, self.database) advice_given.add(advice.advice_id) self.database.email_history.update_one( {'_id': user_id}, {'$set': {'advice_modules.%s' % advice.advice_id: mock_now().isoformat() + 'Z'}}, upsert=True, ) mock_now.return_value = datetime.datetime(2017, 4, 7, 13, 00) advice = advisor.select_advice_for_email(user, user_pb2.FRIDAY, self.database) advice_given.add(advice.advice_id) self.assertEqual(3, len(advice_given), msg=advice_given)
def test_too_many_requests_but_still_enough(self, mock_requests): """Test too many requests but already done more than 200.""" mock_db = mongomock.MongoClient().test mock_db.user.insert_many([{ '_id': mongomock.ObjectId('7ed900dbfbebdee97f9e2{:03d}'.format(i)), 'registeredAt': '2017-11-17T10:57:12Z', } for i in range(400)]) patcher = mock.patch(sync_amplitude.__name__ + '._DB', new=mock_db) patcher.start() self.addCleanup(patcher.stop) # Reply politely to the 300 first. for i in range(300): mock_requests.get( 'https://amplitude.com/api/2/usersearch?user=7ed900dbfbebdee97f9e2{:03d}' .format(i), json={'matches': [{ 'amplitude_id': i }]}, ) mock_requests.get( 'https://amplitude.com/api/2/useractivity?user={}'.format(i), json={'events': []}) # Then reply with an error 429. for i in range(100): mock_requests.get( 'https://amplitude.com/api/2/usersearch?user=7ed900dbfbebdee97f9e2{:03d}' .format(i + 300), status_code=429, reason='429 Client Error: Too many requests for url', ) sync_amplitude.main([ '--registered-from', '2017-11-14', '--registered-to', '2017-11-18', '--disable-sentry', '--no-dry-run' ]) self.assertEqual( 300, len( list( mock_db.user.find( {'clientMetrics.amplitudeId': { '$exists': True }}))))
def test_dry_run(self, mock_requests: requests_mock.Mocker, mock_logging: mock.MagicMock) -> None: """Test update_users_client_metrics.""" mock_db = mongomock.MongoClient().test mock_db.user.insert_one({ '_id': mongomock.ObjectId('7ed900dbfbebdee97f9e2332'), 'registeredAt': '2017-11-17T10:57:12Z', }) patcher = mock.patch(sync_amplitude.__name__ + '._DB', new=mock_db) patcher.start() self.addCleanup(patcher.stop) mock_requests.get( 'https://amplitude.com/api/2/usersearch?user=7ed900dbfbebdee97f9e2332', json={'matches': [{ 'amplitude_id': 42 }]}) mock_requests.get('https://amplitude.com/api/2/useractivity?user=42', json={ 'events': [ { 'event_time': '2017-10-24 10:41:00.412000' }, { 'event_time': '2017-10-24 11:06:05.512000' }, ] }) sync_amplitude.main([ '--registered-from', '2017-11-14', '--registered-to', '2017-11-18', '--disable-sentry' ]) user = user_pb2.User() proto.parse_from_mongo(mock_db.user.find_one({}), user) self.assertFalse(user.client_metrics.amplitude_id) self.assertFalse(user.client_metrics.first_session_duration_seconds) self.assertFalse(user.client_metrics.is_first_session_mobile) mock_logging.assert_called_once()
def test_too_many_requests_but_still_enough( self, mock_requests: requests_mock.Mocker) -> None: """Test too many requests but already done more than 200.""" self._user_db.user.insert_many([{ '_id': mongomock.ObjectId(f'7ed900dbfbebdee97f9e2{i:03d}'), 'registeredAt': '2017-11-17T10:57:12Z', } for i in range(400)]) # Reply politely to the 300 first. for i in range(300): mock_requests.get( f'https://amplitude.com/api/2/usersearch?user=7ed900dbfbebdee97f9e2{i:03d}', json={'matches': [{ 'amplitude_id': i }]}, ) mock_requests.get( f'https://amplitude.com/api/2/useractivity?user={i}', json={'events': []}) # Then reply with an error 429. for i in range(100): mock_requests.get( f'https://amplitude.com/api/2/usersearch?user=7ed900dbfbebdee97f9e2{i + 300:03d}', status_code=429, reason='429 Client Error: Too many requests for url', ) sync_amplitude.main([ '--registered-from', '2017-11-14', '--registered-to', '2017-11-18', '--disable-sentry', '--no-dry-run' ]) self.assertEqual( 300, len( list( self._user_db.user.find( {'clientMetrics.amplitudeId': { '$exists': True }}))))
def _assert_user_receives_focus(self, should_be_sent: bool = True) -> None: json_user = json_format.MessageToDict(self.user) json_user['_id'] = mongomock.ObjectId(json_user.pop('userId')) self._user_database.get_collection( self.mongo_collection).insert_one(json_user) with mock.patch(focus.__name__ + '._POTENTIAL_CAMPAIGNS', {self.campaign_id}): focus.main([ 'send', '--disable-sentry', ]) all_sent_messages = mailjetmock.get_all_sent_messages() if not should_be_sent: self.assertFalse(all_sent_messages) return self.assertEqual(1, len(all_sent_messages), msg=all_sent_messages) self.assertEqual(self.campaign_id, all_sent_messages[0].properties['CustomCampaign']) self._variables = all_sent_messages[0].properties['Variables']