def test_question_topics(self): """Search questions for topics.""" t1 = old_topic(slug="doesnotexist", save=True) t2 = old_topic(slug="cookies", save=True) t3 = old_topic(slug="sync", save=True) # TODO: This is a hack until we move questions to new topics. # We need to create these for the search form validation. topic(slug="doesnotexist", save=True) topic(slug="cookies", save=True) topic(slug="sync", save=True) q = question(save=True) q.topics.add(t2) q = question(save=True) q.topics.add(t2) q.topics.add(t3) self.refresh() topic_vals = ((t1.slug, 0), (t2.slug, 2), (t3.slug, 1), ([t2.slug, t3.slug], 1)) qs = {"a": 1, "w": 2, "format": "json"} for topics, number in topic_vals: qs.update({"topics": topics}) response = self.client.get(reverse("search"), qs) eq_(number, json.loads(response.content)["total"])
def test_lock_old_questions(self): last_updated = datetime.now() - timedelta(days=100) # created just now q1 = question(save=True) # created 200 days ago q2 = question(created=(datetime.now() - timedelta(days=200)), updated=last_updated, save=True) # created 200 days ago, already locked q3 = question(created=(datetime.now() - timedelta(days=200)), is_locked=True, updated=last_updated, save=True) self.refresh() auto_lock_old_questions() # There are three questions. eq_(len(list(Question.objects.all())), 3) # q2 and q3 are now locked and updated times are the same locked_questions = list(Question.uncached.filter(is_locked=True)) eq_(sorted([(q.id, q.updated.date()) for q in locked_questions]), [(q.id, q.updated.date()) for q in [q2, q3]]) # q1 is still unlocked. locked_questions = list(Question.uncached.filter(is_locked=False)) eq_(sorted([q.id for q in locked_questions]), [q1.id])
def test_locale_filter(self): """Only questions for the current locale should be shown on the questions front page for AAQ locales.""" eq_(Question.objects.count(), 0) p = product(slug=u"firefox", save=True) topic(title="Fix problems", slug="fix-problems", product=p, save=True) q1 = question(title="question cupcakes?", save=True, locale="en-US") q1.products.add(p) q2 = question(title="question donuts?", save=True, locale="en-US") q2.products.add(p) q3 = question(title="question pies?", save=True, locale="pt-BR") q3.products.add(p) q4 = question(title="question pastries?", save=True, locale="de") q4.products.add(p) def sub_test(locale, *titles): url = urlparams(reverse("questions.questions", locale=locale)) response = self.client.get(url, follow=True) doc = pq(response.content) eq_msg(len(doc("section[id^=question]")), len(titles), "Wrong number of results for {0}".format(locale)) for substr in titles: assert substr in doc(".questions section .content h2 a").text() # en-US and pt-BR are both in AAQ_LANGUAGES, so should be filtered. sub_test("en-US", "cupcakes?", "donuts?") sub_test("pt-BR", "pies?") # de is not in AAQ_LANGUAGES, so should show en-US, but not pt-BR sub_test("de", "cupcakes?", "donuts?", "pastries?")
def test_visit_count_from_analytics(self, pageviews_by_question): """Verify stored visit counts from mocked data.""" q1 = question(save=True) q2 = question(save=True) q3 = question(save=True) pageviews_by_question.return_value = { q1.id: 42, q2.id: 27, q3.id: 1337, 123459: 3, } QuestionVisits.reload_from_analytics() eq_(3, QuestionVisits.objects.count()) eq_(42, QuestionVisits.objects.get(question_id=q1.id).visits) eq_(27, QuestionVisits.objects.get(question_id=q2.id).visits) eq_(1337, QuestionVisits.objects.get(question_id=q3.id).visits) # Change the data and run again to cover the update case. pageviews_by_question.return_value = { q1.id: 100, q2.id: 200, q3.id: 300, } QuestionVisits.reload_from_analytics() eq_(3, QuestionVisits.uncached.count()) eq_(100, QuestionVisits.uncached.get(question_id=q1.id).visits) eq_(200, QuestionVisits.uncached.get(question_id=q2.id).visits) eq_(300, QuestionVisits.uncached.get(question_id=q3.id).visits)
def test_search_suggestion_questions_locale(self): """Verifies the right languages show up in search suggestions.""" p = product(slug=u"firefox", save=True) topic(title="Fix problems", slug="fix-problems", product=p, save=True) q1 = question(title="question cupcakes?", save=True, locale="en-US") q1.products.add(p) q2 = question(title="question donuts?", save=True, locale="en-US") q2.products.add(p) q3 = question(title="question pies?", save=True, locale="pt-BR") q3.products.add(p) q4 = question(title="question pastries?", save=True, locale="de") q4.products.add(p) self.refresh() def sub_test(locale, *titles): url = urlparams( reverse("questions.aaq_step4", args=["desktop", "fix-problems"], locale=locale), search="question" ) response = self.client.get(url, follow=True) doc = pq(response.content) eq_msg(len(doc(".result.question")), len(titles), "Wrong number of results for {0}".format(locale)) for substr in titles: assert substr in doc(".result.question h3 a").text() sub_test("en-US", "cupcakes?", "donuts?") sub_test("pt-BR", "cupcakes?", "donuts?", "pies?") sub_test("de", "cupcakes?", "donuts?", "pastries?")
def test_created(self): """Basic functionality of created filter.""" created_ds = datetime(2010, 6, 19, 12, 00) # on 6/19/2010 q1 = question(title=u"q1 audio", created=created_ds, save=True) q1.tags.add(u"desktop") ans = answer(question=q1, save=True) answervote(answer=ans, helpful=True, save=True) # on 6/21/2010 q2 = question(title=u"q2 audio", created=(created_ds + timedelta(days=2)), save=True) q2.tags.add(u"desktop") ans = answer(question=q2, save=True) answervote(answer=ans, helpful=True, save=True) self.refresh() qs = {"a": 1, "w": 2, "format": "json", "sortby": 2, "created_date": "06/20/2010"} qs["created"] = constants.INTERVAL_BEFORE response = self.client.get(reverse("search"), qs) results = json.loads(response.content)["results"] eq_([q1.get_absolute_url()], [r["url"] for r in results]) qs["created"] = constants.INTERVAL_AFTER response = self.client.get(reverse("search"), qs) results = json.loads(response.content)["results"] eq_([q2.get_absolute_url()], [r["url"] for r in results])
def test_question_products(self): """Search questions for products.""" p1 = product(slug='b2g', save=True) p2 = product(slug='mobile', save=True) p3 = product(slug='desktop', save=True) q = question(save=True) q.products.add(p2) q = question(save=True) q.products.add(p2) q.products.add(p3) self.refresh() product_vals = ( (p1.slug, 0), (p2.slug, 2), (p3.slug, 1), ([p2.slug, p3.slug], 1), ) qs = {'a': 1, 'w': 2, 'format': 'json'} for products, number in product_vals: qs.update({'product': products}) response = self.client.get(reverse('search'), qs) eq_(number, json.loads(response.content)['total'])
def test_question_topics(self): """Search questions for topics.""" t1 = old_topic(slug='doesnotexist', save=True) t2 = old_topic(slug='cookies', save=True) t3 = old_topic(slug='sync', save=True) # TODO: This is a hack until we move questions to new topics. # We need to create these for the search form validation. topic(slug='doesnotexist', save=True) topic(slug='cookies', save=True) topic(slug='sync', save=True) q = question(save=True) q.topics.add(t2) q = question(save=True) q.topics.add(t2) q.topics.add(t3) self.refresh() topic_vals = ( (t1.slug, 0), (t2.slug, 2), (t3.slug, 1), ([t2.slug, t3.slug], 1), ) qs = {'a': 1, 'w': 2, 'format': 'json'} for topics, number in topic_vals: qs.update({'topics': topics}) response = self.client.get(reverse('search'), qs) eq_(number, json.loads(response.content)['total'])
def test_autowatch_reply(self, get_current): """ Tests the autowatch setting of users. If a user has the setting turned on, they should get notifications after posting in a thread for that thread. If they have that setting turned off, they should not. """ get_current.return_value.domain = 'testserver' u = user(save=True) t1 = question(save=True) t2 = question(save=True) assert not QuestionReplyEvent.is_notifying(u, t1) assert not QuestionReplyEvent.is_notifying(u, t2) self.client.login(username=u.username, password='******') s = Setting.objects.create(user=u, name='questions_watch_after_reply', value='True') data = {'content': 'some content'} post(self.client, 'questions.reply', data, args=[t1.id]) assert QuestionReplyEvent.is_notifying(u, t1) s.value = 'False' s.save() post(self.client, 'questions.reply', data, args=[t2.id]) assert not QuestionReplyEvent.is_notifying(u, t2)
def test_search_suggestion_questions_locale(self): """Verifies the right languages show up in search suggestions.""" topic(title='Fix problems', slug='fix-problems', save=True) p = product(slug=u'firefox', save=True) q1 = question(title='question cupcakes?', save=True, locale='en-US') q1.products.add(p) q2 = question(title='question donuts?', save=True, locale='en-US') q2.products.add(p) q3 = question(title='question pies?', save=True, locale='pt-BR') q3.products.add(p) q4 = question(title='question pastries?', save=True, locale='de') q4.products.add(p) self.refresh() def sub_test(locale, *titles): url = urlparams(reverse('questions.aaq_step4', args=['desktop', 'fix-problems'], locale=locale), search='question') response = self.client.get(url, follow=True) doc = pq(response.content) eq_msg(len(doc('.result.question')), len(titles), 'Wrong number of results for {0}'.format(locale)) for substr in titles: assert substr in doc('.result.question h3 a').text() sub_test('en-US', 'cupcakes?', 'donuts?') sub_test('pt-BR', 'cupcakes?', 'donuts?', 'pies?') sub_test('de', 'cupcakes?', 'donuts?', 'pastries?')
def test_locale_filter(self): """Only questions for the current locale should be shown on the questions front page for AAQ locales.""" eq_(Question.objects.count(), 0) topic(title='Fix problems', slug='fix-problems', save=True) p = product(slug=u'firefox', save=True) q1 = question(title='question cupcakes?', save=True, locale='en-US') q1.products.add(p) q2 = question(title='question donuts?', save=True, locale='en-US') q2.products.add(p) q3 = question(title='question pies?', save=True, locale='pt-BR') q3.products.add(p) q4 = question(title='question pastries?', save=True, locale='de') q4.products.add(p) def sub_test(locale, *titles): url = urlparams(reverse('questions.questions', locale=locale)) response = self.client.get(url, follow=True) doc = pq(response.content) eq_msg(len(doc('section[id^=question]')), len(titles), 'Wrong number of results for {0}'.format(locale)) for substr in titles: assert substr in doc('.questions section .content h2 a').text() # en-US and pt-BR are both in AAQ_LOCALES, so should be filtered. sub_test('en-US', 'cupcakes?', 'donuts?') sub_test('pt-BR', 'pies?') # de is not in AAQ_LOCALES, so should show en-US, but not pt-BR sub_test('de', 'cupcakes?', 'donuts?', 'pastries?')
def test_is_not_taken(self): u = user(save=True) taken_until = datetime.now() + timedelta(seconds=30) question(taken_by=u, taken_until=taken_until, save=True) q = question(save=True) res = self.filter_instance.filter_is_taken(self.queryset, False) eq_(list(res), [q])
def test_search_suggestion_question_age(self): """Verifies the view doesn't return old questions.""" topic(title='Fix problems', slug='fix-problems', save=True) p = product(slug=u'firefox', save=True) q1 = question(title='Fresh Cupcakes', save=True) q1.products.add(p) max_age = settings.SEARCH_DEFAULT_MAX_QUESTION_AGE too_old = datetime.now() - timedelta(seconds=max_age * 2) q2 = question(title='Stale Cupcakes', created=too_old, updated=too_old, save=True) q2.products.add(p) self.refresh() url = urlparams( reverse('questions.aaq_step4', args=['desktop', 'fix-problems']), search='cupcakes') response = self.client.get(url, follow=True) eq_(200, response.status_code) self.assertContains(response, q1.title) self.assertNotContains(response, q2.title)
def test_created(self): """Basic functionality of created filter.""" created_ds = datetime(2010, 6, 19, 12, 00) # on 6/19/2010 q1 = question(title=u'q1 audio', created=created_ds, save=True) q1.tags.add(u'desktop') ans = answer(question=q1, save=True) answervote(answer=ans, helpful=True, save=True) # on 6/21/2010 q2 = question(title=u'q2 audio', created=(created_ds + timedelta(days=2)), save=True) q2.tags.add(u'desktop') ans = answer(question=q2, save=True) answervote(answer=ans, helpful=True, save=True) self.refresh() qs = {'a': 1, 'w': 2, 'format': 'json', 'sortby': 2, 'created_date': '06/20/2010'} qs['created'] = constants.INTERVAL_BEFORE response = self.client.get(reverse('search'), qs) results = json.loads(response.content)['results'] eq_([q1.get_absolute_url()], [r['url'] for r in results]) qs['created'] = constants.INTERVAL_AFTER response = self.client.get(reverse('search'), qs) results = json.loads(response.content)['results'] eq_([q2.get_absolute_url()], [r['url'] for r in results])
def test_question_topics(self): """Search questions for topics.""" p = product(save=True) t1 = topic(slug='doesnotexist', product=p, save=True) t2 = topic(slug='cookies', product=p, save=True) t3 = topic(slug='sync', product=p, save=True) q = question(save=True) q.topics.add(t2) q = question(save=True) q.topics.add(t2) q.topics.add(t3) self.refresh() topic_vals = ( (t1.slug, 0), (t2.slug, 2), (t3.slug, 1), ([t2.slug, t3.slug], 1), ) qs = {'a': 1, 'w': 2, 'format': 'json'} for topics, number in topic_vals: qs.update({'topics': topics}) response = self.client.get(reverse('search'), qs) eq_(number, json.loads(response.content)['total'])
def test_filter_creator_with_username(self): q1 = question(save=True) question(save=True) querystring = '?creator={0}'.format(q1.creator.username) res = self.client.get(reverse('question-list') + querystring) eq_(res.status_code, 200) eq_(len(res.data['results']), 1) eq_(res.data['results'][0]['id'], q1.id)
def test_it_works_with_users_who_have_gotten_first_contrib_emails(self): # This flag caused a regression, tracked in bug 1163855. # The error was that the help text on the field was a str instead of a # unicode. Yes, really, that matters apparently. u = profile(first_answer_email_sent=True).user question(creator=u, save=True) url = reverse('question-list') res = self.client.get(url) eq_(res.status_code, 200)
def test_filter_product_with_slug(self): p1 = product(save=True) p2 = product(save=True) q1 = question(product=p1, save=True) question(product=p2, save=True) querystring = '?product={0}'.format(p1.slug) res = self.client.get(reverse('question-list') + querystring) eq_(len(res.data['results']), 1) eq_(res.data['results'][0]['id'], q1.id)
def test_filter_is_taken_false(self): q1 = question(save=True) q2 = question(save=True) q2.take(q1.creator) url = reverse('question-list') + '?is_taken=0' res = self.client.get(url) eq_(res.status_code, 200) eq_(res.data['count'], 1) eq_(res.data['results'][0]['id'], q1.id)
def test_filter_taken_by_username(self): q1 = question(save=True) q2 = question(save=True) q2.take(q1.creator) url = reverse('question-list') + '?taken_by=' + q1.creator.username res = self.client.get(url) eq_(res.status_code, 200) eq_(res.data['count'], 1) eq_(res.data['results'][0]['id'], q2.id)
def test_filter_is_solved(self): q1 = question(save=True) a1 = answer(question=q1, save=True) q1.solution = a1 q1.save() q2 = question(save=True) res = self.filter.filter_is_solved(self.qs, True) eq_(list(res), [q1]) res = self.filter.filter_is_solved(self.qs, False) eq_(list(res), [q2])
def test_filter_involved(self): q1 = question(save=True) a1 = answer(question=q1, save=True) q2 = question(creator=a1.creator, save=True) qs = self.filter_instance.filter_involved(self.queryset, q1.creator.username) eq_(list(qs), [q1]) qs = self.filter_instance.filter_involved(self.queryset, q2.creator.username) # The filter does not have a strong order. qs = sorted(qs, key=lambda q: q.id) eq_(qs, [q1, q2])
def test_filter_is_solved(self): q1 = question(save=True) a1 = answer(question=q1, save=True) q1.solution = a1 q1.save() q2 = question(save=True) qs = self.filter_instance.filter_is_solved(self.queryset, True) eq_(list(qs), [q1]) qs = self.filter_instance.filter_is_solved(self.queryset, False) eq_(list(qs), [q2])
def test_user_num_questions(self): """Answers are counted correctly on a user.""" u = user(save=True) eq_(user_num_questions(u), 0) q1 = question(creator=u, save=True) eq_(user_num_questions(u), 1) q2 = question(creator=u, save=True) eq_(user_num_questions(u), 2) q1.delete() eq_(user_num_questions(u), 1) q2.delete() eq_(user_num_questions(u), 0)
def test_age(self): now = datetime.now() ten_days_ago = now - timedelta(days=10) thirty_seconds_ago = now - timedelta(seconds=30) q1 = question(created=ten_days_ago, save=True) q2 = question(created=thirty_seconds_ago, save=True) # This test relies on datetime.now() being called in the age # property, so this delta check makes it less likely to fail # randomly. assert abs(q1.age - 10 * 24 * 60 * 60) < 2, ('q1.age ({0!s}) != 10 days'.format(q1.age)) assert abs(q2.age - 30) < 2, 'q2.age ({0!s}) != 30 seconds'.format(q2.age)
def test_escalate_questions_cron(self, submit_ticket): """Verify the escalate cronjob escalates the right questions.""" questions_to_escalate = [ # Questions over 24 hours old without an answer. question( created=datetime.now() - timedelta(hours=24, minutes=10), save=True), question( created=datetime.now() - timedelta(hours=24, minutes=50), save=True), ] questions_not_to_escalate = [ # Questions newer than 24 hours without an answer. question(save=True), question(created=datetime.now() - timedelta(hours=11), save=True), question(created=datetime.now() - timedelta(hours=21), save=True), ] # Question older than 24 hours with a recent answer. q = question( created=datetime.now() - timedelta(hours=24, minutes=10), save=True) answer(created=datetime.now() - timedelta(hours=10), question=q, save=True) answer(created=datetime.now() - timedelta(hours=1), creator=q.creator, question=q, save=True) questions_not_to_escalate.append(q) # Question older than 24 hours with a recent answer by the asker. q = question( created=datetime.now() - timedelta(hours=24, minutes=10), save=True) answer( created=datetime.now() - timedelta(hours=15), creator=q.creator, question=q, save=True) questions_not_to_escalate.append(q) # Question older than 24 hours without an answer already escalated. q = question( created=datetime.now() - timedelta(hours=24, minutes=10), save=True) q.tags.add(config.ESCALATE_TAG_NAME) questions_not_to_escalate.append(q) # Question with an inactive user. q = question( created=datetime.now() - timedelta(hours=24, minutes=10), save=True) q.creator.is_active = False q.creator.save() questions_not_to_escalate.append(q) # Run the cron job and verify only 3 questions were escalated. eq_(len(questions_to_escalate), escalate_questions())
def test_recent_counts_with_filter(self): """Verify that recent_asked_count and recent_unanswered_count respect filters passed.""" now = datetime.now() question(created=now, locale='en-US', save=True) q = question(created=now, locale='en-US', save=True) answer(question=q, save=True) question(created=now, locale='pt-BR', save=True) question(created=now, locale='pt-BR', save=True) q = question(created=now, locale='pt-BR', save=True) answer(question=q, save=True) # 5 asked recently, 3 are unanswered eq_(5, Question.recent_asked_count()) eq_(3, Question.recent_unanswered_count()) # check english (2 asked, 1 unanswered) locale_filter = Q(locale='en-US') eq_(2, Question.recent_asked_count(locale_filter)) eq_(1, Question.recent_unanswered_count(locale_filter)) # check pt-BR (3 asked, 2 unanswered) locale_filter = Q(locale='pt-BR') eq_(3, Question.recent_asked_count(locale_filter)) eq_(2, Question.recent_unanswered_count(locale_filter))
def test_ordering(self): q1 = question(save=True) q2 = question(save=True) res = self.client.get(reverse('question-list')) eq_(res.data['results'][0]['id'], q2.id) eq_(res.data['results'][1]['id'], q1.id) res = self.client.get(reverse('question-list') + '?ordering=id') eq_(res.data['results'][0]['id'], q1.id) eq_(res.data['results'][1]['id'], q2.id) res = self.client.get(reverse('question-list') + '?ordering=-id') eq_(res.data['results'][0]['id'], q2.id) eq_(res.data['results'][1]['id'], q1.id)
def test_answer_welcome_email(self): u1 = profile().user u2 = profile(first_answer_email_sent=True).user u3 = profile().user two_days = datetime.now() - timedelta(hours=48) q = question(creator=u1, save=True) answer(question=q, creator=u1, created=two_days, save=True) answer(question=q, creator=u2, created=two_days, save=True) answer(question=q, creator=u3, created=two_days, save=True) # Clear out the notifications that were sent mail.outbox = [] # Send email(s) for welcome messages cron.send_welcome_emails() # There should be an email for u3 only. # u1 was the asker, and so did not make a contribution. # u2 has already recieved the email eq_(len(mail.outbox), 1) attrs_eq(mail.outbox[0], to=[u3.email]) # u3's flag should now be set. u3 = User.objects.get(id=u3.id) eq_(u3.profile.first_answer_email_sent, True)
def test_from_url(self): """Verify question returned from valid URL.""" q = question(save=True) eq_(q, Question.from_url('/en-US/questions/%s' % q.id)) eq_(q, Question.from_url('/es/questions/%s' % q.id)) eq_(q, Question.from_url('/questions/%s' % q.id))
def test_helpful(self): q = question(save=True) u = profile().user self.client.force_authenticate(user=u) res = self.client.post(reverse('question-helpful', args=[q.id])) eq_(res.status_code, 200) eq_(res.data, {'num_votes': 1}) eq_(Question.objects.get(id=q.id).num_votes, 1)
def test_from_invalid_url(self): """Verify question returned from valid URL.""" q = question(save=True) eq_(None, Question.from_url('/en-US/questions/%s/edit' % q.id)) eq_(None, Question.from_url('/en-US/kb/%s' % q.id)) eq_(None, Question.from_url('/random/url')) eq_(None, Question.from_url('/en-US/questions/dashboard/metrics'))
def test_advanced_search_questions_sortby(self): """Tests advanced search for questions with a sortby""" question(title=u'tags tags tags', save=True) self.refresh() # Advanced search for questions with sortby set to 3 which is # '-replies' which is different between Sphinx and ES. response = self.client.get(reverse('search'), { 'q': 'tags', 'tags': 'desktop', 'w': '2', 'a': '1', 'sortby': '3', 'format': 'json' }) eq_(200, response.status_code) content = json.loads(response.content) eq_(content['total'], 1)
def setUp(self): p = profile() p.save() self.user = p.user self.client.login(username=self.user.username, password='******') self.question = question(creator=self.user, save=True) QuestionReplyEvent.notify(self.user, self.question)
def test_vote_updates_count(self): q = question(save=True) eq_(0, q.num_votes_past_week) questionvote(question=q, anonymous_id='abc123', save=True) q = Question.uncached.get(id=q.id) eq_(1, q.num_votes_past_week)
def test_answer_create_action(self): """When an answer is created, an Action is created too.""" q = question(save=True) ans = answer(question=q, save=True) act = Action.objects.action_object(ans).get() eq_(act.actor, ans.creator) eq_(act.verb, 'answered') eq_(act.target, q)
def test_search_suggestion_questions_locale(self): """Verifies the right languages show up in search suggestions.""" questionlocale(locale='de', save=True) p = product(slug=u'firefox', save=True) for l in QuestionLocale.objects.all(): p.questions_locales.add(l) topic(title='Fix problems', slug='fix-problems', product=p, save=True) q1 = question(title='question cupcakes?', product=p, save=True, locale='en-US') q2 = question(title='question donuts?', product=p, save=True, locale='en-US') q3 = question(title='question pies?', product=p, save=True, locale='pt-BR') q4 = question(title='question pastries?', product=p, save=True, locale='de') self.refresh() def sub_test(locale, *titles): url = urlparams(reverse('questions.aaq_step4', args=['desktop', 'fix-problems'], locale=locale), search='question') response = self.client.get(url, follow=True) doc = pq(response.content) eq_msg(len(doc('.result.question')), len(titles), 'Wrong number of results for {0}'.format(locale)) for substr in titles: assert substr in doc('.result.question h3 a').text() sub_test('en-US', 'cupcakes?', 'donuts?') sub_test('pt-BR', 'cupcakes?', 'donuts?', 'pies?') sub_test('de', 'cupcakes?', 'donuts?', 'pastries?')
def test_questions_by_product(self): """Test product filtering of questions API call.""" firefox_os = product(slug='firefox-os', save=True) firefox = product(slug='firefox', save=True) # A Firefox OS question with a solution: q = question(save=True) q.products.add(firefox_os) a = answer(question=q, save=True) q.solution = a q.save() # A Firefox OS question with an answer: q = question(save=True) q.products.add(firefox_os) answer(question=q, save=True) # A Firefox OS question without answers: q = question(save=True) q.products.add(firefox_os) # A Firefox question without answers: q = question(locale='pt-BR', save=True) q.products.add(firefox) # Verify no product filtering: r = self._get_api_result('api.kpi.questions') eq_(r['objects'][0]['solved'], 1) eq_(r['objects'][0]['responded_24'], 2) eq_(r['objects'][0]['responded_72'], 2) eq_(r['objects'][0]['questions'], 4) # Verify product=firefox-os r = self._get_api_result('api.kpi.questions', product='firefox-os') eq_(r['objects'][0]['solved'], 1) eq_(r['objects'][0]['responded_24'], 2) eq_(r['objects'][0]['responded_72'], 2) eq_(r['objects'][0]['questions'], 3) # Verify product=firefox r = self._get_api_result('api.kpi.questions', product='firefox') eq_(r['objects'][0]['questions'], 1) assert 'solved' not in r['objects'][0] assert 'responded_24' not in r['objects'][0] assert 'responded_72' not in r['objects'][0]
def test_weird_list_troubleshooting_info(self): """Test the corner case in which 'modifiedPReferences' is in a list in troubleshooting data. This is weird, but caused a bug.""" q = question(save=True) q.add_metadata(troubleshooting='["modifiedPreferences"]') # This case should not raise an error. response = get(self.client, 'questions.details', args=[q.id]) eq_(200, response.status_code)
def test_solution_is_readonly(self): q = question(save=True) a = answer(question=q, save=True) self.data['solution'] = a.id serializer = api.QuestionSerializer(context=self.context, data=self.data, instance=q) serializer.save() eq_(q.solution, None)
def test_filter_involved(self): q1 = question(save=True) a1 = answer(question=q1, save=True) q2 = question(creator=a1.creator, save=True) querystring = '?involved={0}'.format(q1.creator.username) res = self.client.get(reverse('question-list') + querystring) eq_(res.status_code, 200) eq_(len(res.data['results']), 1) eq_(res.data['results'][0]['id'], q1.id) querystring = '?involved={0}'.format(q2.creator.username) res = self.client.get(reverse('question-list') + querystring) eq_(res.status_code, 200) eq_(len(res.data['results']), 2) # The API has a default sort, so ordering will be consistent. eq_(res.data['results'][0]['id'], q2.id) eq_(res.data['results'][1]['id'], q1.id)
def test_tagged_feed(self): """Test the tagged feed.""" t = tag(name='green', slug='green', save=True) q = question(save=True) q.tags.add('green') items = TaggedQuestionsFeed().items(t) eq_(1, len(items)) eq_(q.id, items[0].id) cache.clear() q = question(save=True) q.tags.add('green') q.updated = datetime.now() + timedelta(days=1) q.save() items = TaggedQuestionsFeed().items(t) eq_(2, len(items)) eq_(q.id, items[0].id)
def test_follow(self): q = question(save=True) u = profile().user self.client.force_authenticate(user=u) res = self.client.post(reverse('question-follow', args=[q.id])) eq_(res.status_code, 204) f = Follow.objects.get(user=u) eq_(f.follow_object, q) eq_(f.actor_only, False)
def test_unfollow(self): q = question(save=True) u = profile().user actstream.actions.follow(u, q, actor_only=False) eq_(Follow.objects.filter(user=u).count(), 1) # pre-condition self.client.force_authenticate(user=u) res = self.client.post(reverse('question-unfollow', args=[q.id])) eq_(res.status_code, 204) eq_(Follow.objects.filter(user=u).count(), 0)
def setUp(self): self.client = APIClient() self.follower = profile().user self.followed = profile().user self.question = question(creator=self.followed, save=True) # The above might make follows, which this test isn't about. Clear them out. Follow.objects.all().delete() follow(self.follower, self.followed)
def test_no_notification_on_update(self): """Saving an existing question does not watch it.""" q = question(save=True) QuestionReplyEvent.stop_notifying(q.creator, q) assert not QuestionReplyEvent.is_notifying(q.creator, q) q.save() assert not QuestionReplyEvent.is_notifying(q.creator, q)
def test_is_taken_clears(self): u = user(save=True) taken_until = datetime.now() - timedelta(seconds=30) q = question(taken_by=u, taken_until=taken_until, save=True) # Testin q.is_taken should clear out ``taken_by`` and ``taken_until``, # since taken_until is in the past. eq_(q.is_taken, False) eq_(q.taken_by, None) eq_(q.taken_until, None)
def test_questions(self): """Test questions API call.""" # A question with a solution: a = answer(save=True) a.question.solution = a a.question.save() # A question with an answer: answer(save=True) # A question without answers: question(save=True) # A locked question that shouldn't be counted for anything question(is_locked=True, save=True) r = self._get_api_result('api.kpi.questions') eq_(r['objects'][0]['solved'], 1) eq_(r['objects'][0]['responded_24'], 2) eq_(r['objects'][0]['responded_72'], 2) eq_(r['objects'][0]['questions'], 3)
def test_done(self): """Verify the done queryset.""" # Create a question, there shouldn't be any done yet. q = question(save=True) eq_(0, Question.objects.done().count()) # Add an answer, there shouldn't be any done yet. a = answer(question=q, save=True) eq_(0, Question.objects.done().count()) # Make it the solution, there should be one done. q.solution = a q.save() eq_(1, Question.objects.done().count()) # Create a locked questions, there should be two done. question(is_locked=True, save=True) eq_(2, Question.objects.done().count())
def setUp(self): super(FlaggedQueueTestCase, self).setUp() q = question(creator=user(save=True), save=True) self.answer = answer(question=q, creator=user(save=True), save=True) self.flagger = user(save=True) u = user(save=True) add_permission(u, FlaggedObject, 'can_moderate') self.client.login(username=u.username, password='******')
def test_stats(self): """Tests questions/dashboard/metrics view""" p = product(save=True) t = topic(title='Websites', slug='websites', product=p, save=True) question(title=u'cupcakes', content=u'Cupcakes rock!', created=datetime.now() - timedelta(days=1), topic=t, save=True) self.refresh() response = self.client.get(reverse('questions.metrics')) eq_(200, response.status_code) # If there's histogram data, this is probably good enough to # denote its existence. assert ' data-graph="[' in response.content
def test_num_votes_none(self): """Tests num_voted filtering where num_votes is ''""" q = question(save=True) questionvote(question=q, save=True) self.refresh() qs = {'q': '', 'w': 2, 'a': 1, 'num_voted': 2, 'num_votes': ''} response = self.client.get(reverse('search'), qs) eq_(200, response.status_code)
def test_user_num_solutions(self): u = user(save=True) q1 = question(save=True) q2 = question(save=True) a1 = answer(creator=u, question=q1, save=True) a2 = answer(creator=u, question=q2, save=True) eq_(user_num_solutions(u), 0) q1.solution = a1 q1.save() eq_(user_num_solutions(u), 1) q2.solution = a2 q2.save() eq_(user_num_solutions(u), 2) q1.solution = None q1.save() eq_(user_num_solutions(u), 1) a2.delete() eq_(user_num_solutions(u), 0)
def test_solve(self): q = question(save=True) a = answer(question=q, save=True) self.client.force_authenticate(user=q.creator) res = self.client.post(reverse('question-solve', args=[q.id]), data={'answer': a.id}) eq_(res.status_code, 204) q = Question.objects.get(id=q.id) eq_(q.solution, a)
def test_helpful_double_vote(self): q = question(save=True) u = profile().user questionvote(question=q, creator=u, save=True) self.client.force_authenticate(user=u) res = self.client.post(reverse('question-helpful', args=[q.id])) eq_(res.status_code, 409) # It's 1, not 0, because one was created above. The failure cause is # if the number of votes is 2, one from above and one from the api call. eq_(Question.objects.get(id=q.id).num_votes, 1)
def test_take_conflict(self): u1 = user(save=True) u2 = user(save=True) taken_until = datetime.now() + timedelta(seconds=30) q = question(save=True, taken_until=taken_until, taken_by=u1) self.client.force_authenticate(user=u2) res = self.client.post(reverse('question-take', args=[q.id])) eq_(res.status_code, 409) q = Question.objects.get(id=q.id) eq_(q.taken_by, u1)
def test_question_is_unindexed_on_creator_delete(self): search = QuestionMappingType.search() q = question(title=u'Does this work?', save=True) self.refresh() eq_(search.query(question_title__match='work').count(), 1) q.creator.delete() self.refresh() eq_(search.query(question_title__match='work').count(), 0)
def test_question_no_answers_deleted(self): search = QuestionMappingType.search() q = question(title=u'Does this work?', save=True) self.refresh() eq_(search.query(question_title__match='work').count(), 1) q.delete() self.refresh() eq_(search.query(question_title__match='work').count(), 0)
def test_filter_solved_by(self): q1 = question(save=True) a1 = answer(question=q1, save=True) q1.solution = a1 q1.save() q2 = question(save=True) answer(question=q2, creator=a1.creator, save=True) q3 = question(save=True) a3 = answer(question=q3, save=True) q3.solution = a3 q3.save() qs = self.filter_instance.filter_solved_by(self.queryset, a1.creator.username) eq_(list(qs), [q1]) qs = self.filter_instance.filter_solved_by(self.queryset, a3.creator.username) eq_(list(qs), [q3])
def test_question_vote_limit(self): """Test that an anonymous user's votes are ignored after 10 question votes.""" questions = [question(save=True) for _ in range(11)] # The rate limit is 10 per day. So make 10 requests. (0 through 9) for i in range(10): self._check_question_vote(questions[i], False) # Now make another, it should fail. self._check_question_vote(questions[10], True)