Home | History | Annotate | Download | only in bug_hunter
      1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 """Unit Tests for bug hunter."""
      6 
      7 import logging
      8 from optparse import Values
      9 import smtplib
     10 import sys
     11 import unittest
     12 
     13 from bug_hunter import BugHunter
     14 from bug_hunter import BugHunterUtils
     15 
     16 try:
     17   import atom.data
     18   import gdata.data
     19   import gdata.projecthosting.client
     20 except ImportError:
     21   logging.error('gdata-client needs to be installed. Please install\n'
     22                 'and try again (http://code.google.com/p/gdata-python-client/)')
     23   sys.exit(1)
     24 
     25 
     26 class MockClient(object):
     27   """A mock class for gdata.projecthosting.client.ProjectHostingClient.
     28 
     29   Mocking the very simple method invocations for get_issues() and
     30   get_comments().
     31   """
     32 
     33   def _CreateIssues(self, n_issues):
     34     feed = gdata.projecthosting.data.IssuesFeed()
     35     for i in xrange(n_issues):
     36       feed.entry.append(gdata.projecthosting.data.IssueEntry(
     37           title=atom.data.Title(text='title'),
     38           content=atom.data.Content(text='http://www.content.com'),
     39           id=atom.data.Id(text='/' + str(i)),
     40           status=gdata.projecthosting.data.Status(text='Unconfirmed'),
     41           state=gdata.projecthosting.data.State(text='open'),
     42           label=[gdata.projecthosting.data.Label('label1')],
     43           author=[atom.data.Author(name=atom.data.Name(text='author'))]))
     44     return feed
     45 
     46   def get_issues(self, project_name, query):
     47     """Get issues using mock object without calling the issue tracker API.
     48 
     49     Based on query argument, this returns the dummy issues. The number of
     50     dummy issues are specified in query.text_query.
     51 
     52     Args:
     53       project_name: A string for project name in the issue tracker.
     54       query: A query object for querying the issue tracker.
     55 
     56     Returns:
     57        A IssuesFeed object that contains a simple test issue.
     58     """
     59     n_issues = 1
     60     if query.text_query.isdigit():
     61       n_issues = int(query.text_query)
     62     return self._CreateIssues(n_issues)
     63 
     64   def get_comments(self, project_name, issue_id):
     65     """Get comments using mock object without calling the issue tracker API.
     66 
     67     Args:
     68       project_name: A string for project name in the issue tracker.
     69       issue_id: Issue_id string.
     70 
     71     Returns:
     72        A CommentsFeed object that contains a simple test comment.
     73     """
     74     feed = gdata.projecthosting.data.CommentsFeed()
     75     feed.entry = [gdata.projecthosting.data.CommentEntry(
     76         id=atom.data.Id(text='/0'),
     77         content=atom.data.Content(text='http://www.comments.com'),
     78         updated=atom.data.Updated(text='Updated'),
     79         author=[atom.data.Author(name=atom.data.Name(text='cauthor'))])]
     80     return feed
     81 
     82 
     83 class BugHunterUnitTest(unittest.TestCase):
     84   """Unit tests for the Bug Hunter class."""
     85 
     86   def setUp(self):
     87     self._old_client = gdata.projecthosting.client.ProjectHostingClient
     88     gdata.projecthosting.client.ProjectHostingClient = MockClient
     89 
     90   def tearDown(self):
     91     gdata.projecthosting.client.ProjectHostingClient = self._old_client
     92 
     93   def _GetDefaultOption(self, set_10_days_ago, query='steps'):
     94     ops = Values()
     95     ops.query = query
     96     if set_10_days_ago:
     97       ops.interval_value = 10
     98       ops.interval_unit = 'days'
     99     else:
    100       ops.interval_value = None
    101     ops.email_entries = ['comments']
    102     ops.project_name = 'chromium'
    103     ops.query_title = 'query title'
    104     ops.max_comments = None
    105     return ops
    106 
    107   def _GetIssue(self, n_issues):
    108     issues = []
    109     for i in xrange(n_issues):
    110       issues.append({'issue_id': str(i), 'title': 'title', 'author': 'author',
    111                      'status': 'status', 'state': 'state',
    112                      'content': 'content', 'comments': [],
    113                      'labels': [], 'urls': []})
    114     return issues
    115 
    116   def testSetUpEmailSubjectMsg(self):
    117     bh = BugHunter(self._GetDefaultOption(False))
    118     subject, content = bh._SetUpEmailSubjectMsg(self._GetIssue(1))
    119     self.assertEquals(subject,
    120                       'BugHunter found 1 query title bug!')
    121     self.assertEquals(content,
    122                       ('<a href="http://code.google.com/p/chromium/issues/'
    123                        'list?can=2&colspec=ID+Pri+Mstone+ReleaseBlock+Area+'
    124                        'Feature+Status+Owner+Summary&cells=tiles&sort=-id&'
    125                        'q=steps">Used Query</a>: steps<br><br>The number of '
    126                        'issues : 1<br><ul><li><a href="http://crbug.com/0">0 '
    127                        'title</a> [] </li></ul>'))
    128 
    129   def testSetUpEmailSubjectMsgMultipleIssues(self):
    130     bh = BugHunter(self._GetDefaultOption(False))
    131     subject, content = bh._SetUpEmailSubjectMsg(self._GetIssue(2))
    132     self.assertEquals(subject,
    133                       'BugHunter found 2 query title bugs!')
    134 
    135   def testSetUpEmailSubjectMsgWith10DaysAgoAndAssertSubject(self):
    136     bh = BugHunter(self._GetDefaultOption(True))
    137     subject, _ = bh._SetUpEmailSubjectMsg(self._GetIssue(1))
    138     self.assertEquals(subject,
    139                       ('BugHunter found 1 query title bug in the past 10 '
    140                        'days!'))
    141 
    142   def testGetIssuesWithMockClient(self):
    143     bh = BugHunter(self._GetDefaultOption(False,
    144                                           query=('dummy')))
    145     expected_issues = [{'issue_id': '0', 'title': 'title', 'author': 'author',
    146                         'status': 'Unconfirmed', 'state': 'open',
    147                         'content': 'http://www.content.com',
    148                         'comments': '', 'labels': ['label1'],
    149                         'urls': ['http://www.content.com']}]
    150     self.assertEquals(expected_issues, bh.GetIssues())
    151 
    152 
    153 class MockSmtp(object):
    154   """A mock class for SMTP."""
    155 
    156   def __init__(self, server):
    157     pass
    158 
    159   def sendmail(self, sender_email_address, receivers_email_addresses,
    160                msg):
    161     # TODO(imasaki): Do something here.
    162     return True
    163 
    164   def quit(self):
    165     pass
    166 
    167 
    168 class BugHunterUtilsTest(unittest.TestCase):
    169   """Unit tests for the Bug Hunter utility."""
    170 
    171   def testStripHTML(self):
    172     self.assertEquals(BugHunterUtils.StripHTML('<p>X</p>'), 'X')
    173 
    174   def testStripHTMLEmpty(self):
    175     self.assertEquals(BugHunterUtils.StripHTML(''), '')
    176 
    177   def testSendEmail(self):
    178     smtplib.SMTP = MockSmtp
    179     self.assertEqual(BugHunterUtils.SendEmail('message', 'sender_email_address',
    180                                               'receivers_email_addresses',
    181                                               'subject'),
    182                      True)
    183