def test_requeue_weekly_saved_search(self): """ Tests that weekly saved searches are requeued correctly individually in addition to as part of a digest. """ today = datetime.date.today() two_days_ago = today.isoweekday() - 2 two_month_days_ago = today.day - 2 if two_days_ago <= 0: # Dates can't be negative or zero two_days_ago += 7 if two_month_days_ago == 0: # According to mysearches/models.py, we can't have saved searches on # the 31st. If two_month_days_ago==0, this would be the 31st. two_days_ago -= 1 digest = SavedSearchDigestFactory(user=self.user, is_active=True) search = SavedSearchFactory(user=self.user, is_active=True, frequency='W', day_of_week=two_days_ago) self.requeue(search, digest) digest.is_active = False digest.save() search.last_sent = None search.save() mail.outbox = [] self.requeue(search, digest)
def test_requeue_monthly_saved_search(self): """ Tests that monthly saved searches are requeued correctly individually in addition to as part of a digest. """ today = datetime.date.today() two_days_ago = today.day - 2 if two_days_ago < 0: two_days_ago += 31 elif two_days_ago == 0: two_days_ago = 30 digest = SavedSearchDigestFactory(user=self.user, is_active=True) search = SavedSearchFactory(user=self.user, is_active=True, frequency='M', day_of_month=two_days_ago) self.requeue(search, digest) digest.is_active = False digest.save() search.last_sent = None search.save() mail.outbox = [] self.requeue(search, digest)
def test_requeue_weekly_saved_search(self): """ Tests that weekly saved searches are requeued correctly individually in addition to as part of a digest. """ today = datetime.date.today() two_days_ago = today.isoweekday() - 2 two_month_days_ago = today.day - 2 if two_days_ago <= 0: # Dates can't be negative or zero two_days_ago += 7 if two_month_days_ago == 0: # According to mysearches/models.py, we can't have saved searches on # the 31st. If two_month_days_ago==0, this would be the 31st. two_days_ago -= 1 digest = SavedSearchDigestFactory(user=self.user, is_active=True) search = SavedSearchFactory(user=self.user, is_active=True, frequency='W', day_of_week=two_days_ago) self.requeue(search, digest) digest.is_active = False digest.save() search.last_sent = None search.save() mail.outbox = [] self.requeue(search, digest)
def test_requeue_monthly_saved_search(self): """ Tests that monthly saved searches are requeued correctly individually in addition to as part of a digest. """ today = datetime.date.today() two_days_ago = today.day - 2 if two_days_ago < 0: two_days_ago += 31 elif two_days_ago == 0: two_days_ago = 30 digest = SavedSearchDigestFactory(user=self.user, is_active=True) search = SavedSearchFactory(user=self.user, is_active=True, frequency='M', day_of_month=two_days_ago) self.requeue(search, digest) digest.is_active = False digest.save() search.last_sent = None search.save() mail.outbox = [] self.requeue(search, digest)
def test_requeue_monthly_saved_search(self): """ Tests that monthly saved searches are requeued correctly individually in addition to as part of a digest. """ today = datetime.date.today().day last_week = today - 7 if last_week <= 0: last_week += 31 digest = SavedSearchDigestFactory(user=self.user, is_active=True) search = SavedSearchFactory(user=self.user, is_active=True, frequency='M', day_of_month=last_week) self.requeue(search, digest) digest.is_active = False digest.save() search.last_sent = None search.save() mail.outbox = [] self.requeue(search, digest)
class PartnerSavedSearchTests(MyJobsBase): def setUp(self): super(PartnerSavedSearchTests, self).setUp() self.user = UserFactory() self.digest = SavedSearchDigestFactory(user=self.user) self.company = CompanyFactory() self.partner = PartnerFactory(owner=self.company) self.contact = ContactFactory(user=self.user, partner=self.partner) self.partner_search = PartnerSavedSearchFactory(user=self.user, created_by=self.user, provider=self.company, partner=self.partner) # Partner searches are normally created with a form, which creates # invitations as a side effect. We're not testing the form, so we # can fake an invitation here. Invitation(invitee_email=self.partner_search.email, invitee=self.partner_search.user, inviting_user=self.partner_search.created_by, inviting_company=self.partner_search.partner.owner, added_saved_search=self.partner_search).save() self.patcher = patch('urllib2.urlopen', return_file()) self.mock_urlopen = self.patcher.start() self.num_occurrences = lambda text, search_str: [match.start() for match in re.finditer( search_str, text)] # classes and ids may get stripped out when pynliner inlines css. # all jobs contain a default (blank) icon, so we can search for that if # we want a job count self.job_icon = 'http://png.nlx.org/100x50/logo.gif' def tearDown(self): super(PartnerSavedSearchTests, self).tearDown() try: self.patcher.stop() except RuntimeError: # patcher was stopped in a test pass def test_send_partner_saved_search_as_saved_search(self): """ When we send saved searches, we assume they are instances of SavedSearch and disregard any subclasses. Ensure that partner saved searches are correctly recorded as sent when this happens. """ search = SavedSearch.objects.get(pk=self.partner_search.pk) mail.outbox = [] self.assertEqual(ContactRecord.objects.count(), 1) self.partner_search.send_email() self.assertEqual(SavedSearchLog.objects.count(), 2) self.assertEqual(ContactRecord.objects.count(), 2) partner_record = ContactRecord.objects.all()[1] partner_email = mail.outbox.pop() search.send_email() self.assertEqual(SavedSearchLog.objects.count(), 3) self.assertEqual(ContactRecord.objects.count(), 3) search_record = ContactRecord.objects.all()[2] search_email = mail.outbox.pop() self.assertEqual(partner_record.notes, search_record.notes) self.assertEqual(partner_email.body, search_email.body) self.assertEqual(partner_record.notes, partner_email.body) self.assertFalse("Your resume is %s%% complete" % self.user.profile_completion in partner_email.body) logs = SavedSearchLog.objects.all()[1:] for log in logs: self.assertTrue(log.was_sent) self.assertIsNotNone(log.contact_record) # These are separate contact records (different pks), but the notes # attached to each are identical. self.assertEqual(logs[0].contact_record.notes, logs[1].contact_record.notes) def test_send_partner_saved_search_in_digest(self): """ Saved search digests bypass the SavedSearch.send_email method. Ensure that partner saved searches are recorded when sent in a digest. """ SavedSearchFactory(user=self.user) self.assertEqual(ContactRecord.objects.count(), 1) self.digest.send_email() self.assertEqual(SavedSearchLog.objects.count(), 2) self.assertEqual(ContactRecord.objects.count(), 2) email = mail.outbox[0] self.assertFalse("Your resume is %s%% complete" % self.user.profile_completion in email.body) log = SavedSearchLog.objects.last() self.assertTrue(log.was_sent) def test_send_partner_saved_search_with_inactive_user(self): self.user.is_active = False self.user.save() mail.outbox = [] self.partner_search.initial_email() email = mail.outbox.pop() self.assertTrue('Your account is not currently active.' in email.body) verify_url = get_activation_link(self.user) profile = ActivationProfile.objects.get(user=self.user, email=self.user.email) self.assertTrue(profile.activation_key in verify_url) self.assertTrue(self.user.user_guid in verify_url) self.assertTrue('https://secure.my.jobs%s' % verify_url in email.body) def test_contact_record_created_by(self): ContactRecord.objects.all().delete() self.partner_search.initial_email() record = ContactRecord.objects.get() self.assertEqual(record.created_by, self.partner_search.created_by) def test_num_occurrences_instance_method(self): # quick sanity checks; searching for a string that doesn't exist # returns an empty list not_found = self.num_occurrences( 'this is not the string you are looking for', self.job_icon) self.assertEqual(not_found, []) # searching for a string that does exist returns all starting indices # for the string found = self.num_occurrences(self.job_icon, self.job_icon) self.assertEqual(found, [0]) def test_partner_saved_search_pads_results(self): """ If a partner saved search results in less than the desired number of results, it should be padded with additional older results. """ self.partner_search.send_email() partner_search_email = mail.outbox.pop() job_count = self.num_occurrences(partner_search_email.body, self.job_icon) self.assertEqual(len(job_count), 2) log = SavedSearchLog.objects.last() self.assertEqual(log.new_jobs, 1) self.assertEqual(log.backfill_jobs, 1) def test_saved_search_new_job_indicator(self): """ Partner saved searches should include indicators for unseen jobs, while job seeker saved searches should not. """ new_job_indicator = '>New! <' search = SavedSearchFactory(user=self.user) search.send_email() search_email = mail.outbox.pop() new_jobs = self.num_occurrences(search_email.body, new_job_indicator) self.assertEqual(len(new_jobs), 0) self.partner_search.send_email() partner_search_email = mail.outbox.pop() new_jobs = self.num_occurrences(partner_search_email.body, new_job_indicator) self.assertEqual(len(new_jobs), 1) def test_partner_saved_search_no_jobs(self): self.partner_search.feed = 'http://google.com' self.partner_search.save() self.partner_search.send_email() email = mail.outbox.pop() self.assertIn('There are no results for today!', email.body) # Confirm last_sent was updated even though there were no jobs. updated_search = SavedSearch.objects.get(pk=self.partner_search.pk) new_last_sent = updated_search.last_sent.replace(tzinfo=None) self.assertNotEqual(self.partner_search.last_sent, new_last_sent) def test_partner_saved_search_digest_no_jobs(self): self.digest.is_active = True self.digest.save() self.partner_search.feed = 'http://google.com' self.partner_search.save() self.partner_search.send_email() for x in range(1, 5): PartnerSavedSearchFactory(user=self.user, created_by=self.user, provider=self.company, feed='http://google.com', partner=self.partner) self.digest.send_email() email = mail.outbox.pop() self.assertEqual(email.body.count('There are no results for today!'), 5) # Confirm last_sent was updated on all searches even though there were # no jobs. kwargs = { 'user': self.user, 'last_sent__isnull': True, } self.assertEqual(SavedSearch.objects.filter(**kwargs).count(), 0)
class PartnerSavedSearchTests(MyJobsBase): def setUp(self): super(PartnerSavedSearchTests, self).setUp() self.digest = SavedSearchDigestFactory(user=self.user) self.company = CompanyFactory() self.partner = PartnerFactory(owner=self.company) self.contact = ContactFactory(user=self.user, partner=self.partner) self.partner_search = PartnerSavedSearchFactory(user=self.user, created_by=self.user, provider=self.company, partner=self.partner) # Partner searches are normally created with a form, which creates # invitations as a side effect. We're not testing the form, so we # can fake an invitation here. invitation = Invitation.objects.create( invitee_email=self.partner_search.email, invitee=self.partner_search.user, inviting_user=self.partner_search.created_by, inviting_company=self.partner_search.partner.owner, added_saved_search=self.partner_search) invitation.send(self.partner_search) self.num_occurrences = lambda text, search_str: [ match.start() for match in re.finditer(search_str, text) ] # classes and ids may get stripped out when pynliner inlines css. # all jobs contain a default (blank) icon, so we can search for that if # we want a job count self.job_icon = 'http://png.nlx.org/100x50/logo.gif' def test_send_partner_saved_search_as_saved_search(self): """ When we send saved searches, we assume they are instances of SavedSearch and disregard any subclasses. Ensure that partner saved searches are correctly recorded as sent when this happens. """ search = SavedSearch.objects.get(pk=self.partner_search.pk) mail.outbox = [] self.assertEqual(ContactRecord.objects.count(), 1) self.partner_search.send_email() self.assertEqual(SavedSearchLog.objects.count(), 2) self.assertEqual(ContactRecord.objects.count(), 2) partner_record = ContactRecord.objects.all()[1] partner_email = mail.outbox.pop() search.send_email() self.assertEqual(SavedSearchLog.objects.count(), 3) self.assertEqual(ContactRecord.objects.count(), 3) search_record = ContactRecord.objects.all()[2] search_email = mail.outbox.pop() self.assertEqual(partner_record.notes, search_record.notes) self.assertEqual(partner_email.body, search_email.body) self.assertEqual(partner_record.notes, partner_email.body) self.assertFalse("Your profile is %s%% complete" % self.user.profile_completion in partner_email.body) logs = SavedSearchLog.objects.all()[1:] for log in logs: self.assertTrue(log.was_sent) self.assertIsNotNone(log.contact_record) # These are separate contact records (different pks), but the notes # attached to each are identical. self.assertEqual(logs[0].contact_record.notes, logs[1].contact_record.notes) def test_send_partner_saved_search_in_digest(self): """ Saved search digests bypass the SavedSearch.send_email method. Ensure that partner saved searches are recorded when sent in a digest. """ SavedSearchFactory(user=self.user) self.assertEqual(ContactRecord.objects.count(), 1) self.digest.send_email() self.assertEqual(SavedSearchLog.objects.count(), 2) self.assertEqual(ContactRecord.objects.count(), 2) email = mail.outbox[0] self.assertFalse("Your profile is %s%% complete" % self.user.profile_completion in email.body) log = SavedSearchLog.objects.last() self.assertTrue(log.was_sent) def test_send_partner_saved_search_with_inactive_user(self): self.user.is_active = False self.user.save() mail.outbox = [] self.partner_search.initial_email() email = mail.outbox.pop() self.assertTrue('Your account is not currently active.' in email.body) verify_url = get_activation_link(self.user) profile = ActivationProfile.objects.get(user=self.user, email=self.user.email) self.assertTrue(profile.activation_key in verify_url) self.assertTrue(self.user.user_guid in verify_url) self.assertTrue('https://secure.my.jobs%s' % verify_url in email.body) def test_contact_record_created_by(self): ContactRecord.objects.all().delete() self.partner_search.initial_email() record = ContactRecord.objects.get() self.assertEqual(record.created_by, self.partner_search.created_by) def test_num_occurrences_instance_method(self): # quick sanity checks; searching for a string that doesn't exist # returns an empty list not_found = self.num_occurrences( 'this is not the string you are looking for', self.job_icon) self.assertEqual(not_found, []) # searching for a string that does exist returns all starting indices # for the string found = self.num_occurrences(self.job_icon, self.job_icon) self.assertEqual(found, [0]) def test_partner_saved_search_pads_results(self): """ If a partner saved search results in less than the desired number of results, it should be padded with additional older results. """ self.partner_search.send_email() partner_search_email = mail.outbox.pop() job_count = self.num_occurrences(partner_search_email.body, self.job_icon) self.assertEqual(len(job_count), 2) log = SavedSearchLog.objects.last() self.assertEqual(log.new_jobs, 1) self.assertEqual(log.backfill_jobs, 1) def test_saved_search_new_job_indicator(self): """ Partner saved searches should include indicators for unseen jobs, while job seeker saved searches should not. """ new_job_indicator = '>New! <' search = SavedSearchFactory(user=self.user) search.send_email() search_email = mail.outbox.pop() new_jobs = self.num_occurrences(search_email.body, new_job_indicator) self.assertEqual(len(new_jobs), 0) self.partner_search.send_email() partner_search_email = mail.outbox.pop() new_jobs = self.num_occurrences(partner_search_email.body, new_job_indicator) self.assertEqual(len(new_jobs), 1) def test_partner_saved_search_no_jobs(self): self.partner_search.feed = 'http://google.com' self.partner_search.save() self.partner_search.send_email() email = mail.outbox.pop() self.assertIn('There are no results for today!', email.body) # Confirm last_sent was updated even though there were no jobs. updated_search = SavedSearch.objects.get(pk=self.partner_search.pk) new_last_sent = updated_search.last_sent.replace(tzinfo=None) self.assertNotEqual(self.partner_search.last_sent, new_last_sent) def test_partner_saved_search_digest_no_jobs(self): self.digest.is_active = True self.digest.save() self.partner_search.feed = 'http://google.com' self.partner_search.save() self.partner_search.send_email() for x in range(1, 5): PartnerSavedSearchFactory(user=self.user, created_by=self.user, provider=self.company, feed='http://google.com', partner=self.partner) self.digest.send_email() email = mail.outbox.pop() self.assertEqual(email.body.count('There are no results for today!'), 5) # Confirm last_sent was updated on all searches even though there were # no jobs. kwargs = { 'user': self.user, 'last_sent__isnull': True, } self.assertEqual(SavedSearch.objects.filter(**kwargs).count(), 0) @freeze_time("2016-10-01 10:01:00") def test_send_pss_after_10(self): """ Ensures that partner saved searches that are created and scheduled for today are sent immediately if they are saved after the batch sending process begins. """ company = CompanyFactory() partner = PartnerFactory(owner=company) communication_records = ContactRecord.objects.count() # The act of creating a daily partner saved search after 10 AM should # send the saved search being created. PartnerSavedSearchFactory(user=self.user, created_by=self.user, provider=company, partner=partner, frequency='D') self.assertEqual(ContactRecord.objects.count(), communication_records + 1, msg=("No communication record after " "daily search creation")) today = datetime.date.today() # Creating a weekly partner saved search with a day_of_week of today # should send the saved search on save. PartnerSavedSearchFactory(user=self.user, created_by=self.user, provider=company, partner=partner, frequency='W', day_of_week=today.isoweekday()) self.assertEqual(ContactRecord.objects.count(), communication_records + 2, msg=("No communication record after " "weekly search creation")) PartnerSavedSearchFactory(user=self.user, created_by=self.user, provider=company, partner=partner, frequency='M', day_of_month=today.day) self.assertEqual(ContactRecord.objects.count(), communication_records + 3, msg=("No communication record after " "monthly search creation"))