Skip to content

Commit

Permalink
add issue existent check for create new bug, tests for bugs and updat…
Browse files Browse the repository at this point in the history
…e_bugs
  • Loading branch information
ira committed Nov 20, 2015
1 parent 285eaa7 commit ccc65a2
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 40 deletions.
118 changes: 118 additions & 0 deletions cdws_api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from common.models import Project, Settings
from testreport.models import TestPlan
from testreport.models import Launch
from testreport.models import Bug
from testreport.models import PASSED, FAILED, INIT_SCRIPT, ASYNC_CALL, SKIPPED
from testreport.models import STOPPED

Expand All @@ -14,6 +15,11 @@

from djcelery.models import PeriodicTask, CrontabSchedule

from testreport.tasks import update_bugs

from django.test.utils import override_settings

import requests_mock
import json
import random
import os
Expand Down Expand Up @@ -57,6 +63,9 @@ def _call_rest(self, method, url,
'of expected values.'.
format(response.status_code))

if not response.content:
return response

if content_type == u'application/json':
return json.loads(response.content.decode('utf-8',
errors='replace'))
Expand Down Expand Up @@ -568,6 +577,115 @@ def test_comment_create(self):
self.assertEqual(comments[0]['comment'], self.comment)


@override_settings(
BUG_TRACKING_SYSTEM_HOST='jira.local',
BUG_TRACKING_SYSTEM_BUG_PATH='/rest/api/latest/issue/{issue_id}',
BUG_STATE_EXPIRED=['Closed'])
class BugsApiTestCase(AbstractEntityApiTestCase):
issue_found = '{"key": "ISSUE-1","fields": ' \
'{"status": {"name": "Closed"},"summary": "Issue Title"}}'
issue_not_found = '{"errorMessages": ' \
'["Issue Does Not Exist"], "errors": { } }'
issue_errors = '{"errorMessages": ' \
'[], "errors": {"project":"project is required"} }'

def issue_request(self, externalId):
return 'https://{}/rest/api/latest/issue/{}'.\
format(settings.BUG_TRACKING_SYSTEM_HOST, externalId)

def _create_bug(self):
data = {
'externalId': 'ISSUE-1',
'regexp': 'Regexp'
}
return self._call_rest('post', 'bugs/', data)

def _create_bug_db(self, extId, regexp, state, name):
Bug.objects.create(externalId=extId, regexp=regexp,
state=state, name=name)

def _get_bugs(self):
return self._call_rest('get', 'bugs/')

@requests_mock.Mocker()
def test_bug_create(self, m):
m.get(self.issue_request('ISSUE-1'), text=self.issue_found)
response = self._create_bug()
self.assertEqual(201, response.status_code)

response = self._get_bugs()
self.assertEqual(1, len(response['results']))
issue = response['results'][0]
self.assertEqual('ISSUE-1', issue['externalId'])
self.assertEqual('Closed', issue['status'])
self.assertEqual('Issue Title', issue['name'])
self.assertEqual('Regexp', issue['regexp'])

@requests_mock.Mocker()
def test_create_not_existent_bug(self, m):
m.get(self.issue_request('ISSUE-1'), text=self.issue_not_found)
response = self._create_bug()
self.assertEqual('Issue Does Not Exist', response['message'])

@requests_mock.Mocker()
def test_create_errors_bug(self, m):
m.get(self.issue_request('ISSUE-1'), text=self.issue_errors)
response = self._create_bug()
self.assertEqual('project', response['message'])

@requests_mock.Mocker()
@override_settings(TIME_BEFORE_UPDATE_BUG_INFO=0)
def test_update_bug_not_exist(self, m):
m.get(self.issue_request('ISSUE-1'), text=self.issue_found)
m.get(self.issue_request('ISSUE-2'), text=self.issue_not_found)

self._create_bug_db('ISSUE-1', 'regexp', 'Open', 'Issue Title')
self._create_bug_db('ISSUE-2', 'regexp', 'Open', 'Issue Title')

update_bugs()
response = self._call_rest('get', 'bugs/1/')
self.assertEqual('Closed', response['status'])
response = self._call_rest('get', 'bugs/2/')
self.assertEqual('Open', response['status'])

@requests_mock.Mocker()
def test_update_bug_recently(self, m):
m.get(self.issue_request('ISSUE-1'), text=self.issue_found)
self._create_bug_db('ISSUE-1', 'regexp', 'Open', 'Issue Title')

update_bugs()
response = self._call_rest('get', 'bugs/1/')
self.assertEqual('Open', response['status'])

@requests_mock.Mocker()
def test_bug_released_change_status(self, m):
m.get(self.issue_request('ISSUE-1'), text=self.issue_found)
self._create_bug_db('ISSUE-1', 'regexp', 'Closed', 'Issue Title')

update_bugs()
response = self._call_rest('get', 'bugs/1/')
self.assertEqual('Closed', response['status'])

@requests_mock.Mocker()
def test_bug_not_expired(self, m):
m.get(self.issue_request('ISSUE-1'), text=self.issue_found)
self._create_bug_db('ISSUE-1', 'regexp', 'Closed', 'Issue Title')

update_bugs()
response = self._call_rest('get', 'bugs/1/')
self.assertEqual('Closed', response['status'])

@requests_mock.Mocker()
@override_settings(BUG_TIME_EXPIRED=0)
def test_bug_expired(self, m):
m.get(self.issue_request('ISSUE-1'), text=self.issue_found)
self._create_bug_db('ISSUE-1', 'regexp', 'Closed', 'Issue Title')

update_bugs()
response = self._get_bugs()
self.assertEqual(0, len(response['results']))


class StagesApiTestCase(AbstractEntityApiTestCase):
def setUp(self):
project = Project.objects.create(name='DummyTestProject')
Expand Down
22 changes: 22 additions & 0 deletions cdws_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
from testreport.models import Bug
from testreport.models import INITIALIZED, ASYNC_CALL, INIT_SCRIPT, CONCLUSIVE
from testreport.models import STOPPED
from testreport.models import get_issue_fields_from_bts

from stages.models import Stage

Expand Down Expand Up @@ -390,6 +391,27 @@ class BugViewSet(viewsets.ModelViewSet):
filter_backends = (DjangoFilterBackend, OrderingFilter, )
filter_fields = ('id', 'externalId')

def create(self, request, *args, **kwargs):
log.info('Check issue {} for existing'.
format(request.DATA['externalId']))
response = get_issue_fields_from_bts(request.DATA['externalId'])

errors = []
if 'errors' in response:
errors += response['errors']
if 'errorMessages' in response:
errors += response['errorMessages']
if len(errors) != 0:
return Response(
data={'message': '\n'.join(errors)},
status=status.HTTP_400_BAD_REQUEST)

Bug.objects.create(externalId=request.DATA['externalId'],
regexp=request.DATA['regexp'],
state=response['status']['name'],
name=response['summary'])
return Response(status=status.HTTP_201_CREATED)


class StageViewSet(GetOrCreateViewSet):
queryset = Stage.objects.all()
Expand Down
1 change: 1 addition & 0 deletions test-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ mock>=1.0
coverage==3.7.1
sqlalchemy
unittest-xml-reporting
requests-mock
24 changes: 24 additions & 0 deletions testreport/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import logging
import json

from django.conf import settings
import requests

log = logging.getLogger(__name__)

TEST_STATES = (PASSED, FAILED, SKIPPED, BLOCKED) = (0, 1, 2, 3)
Expand Down Expand Up @@ -159,3 +162,24 @@ def get_state(self):

def __unicode__(self):
return ':'.join((self.externalId, self.name))


def get_issue_fields_from_bts(externalId):
log.debug('Get fields for bug {}'.format(externalId))
res = _get_bug(externalId)
if 'fields' in res:
return res['fields']
return res


def _get_bug(bug_id):
response = requests.get(
'https://{}{}'.format(
settings.BUG_TRACKING_SYSTEM_HOST,
settings.BUG_TRACKING_SYSTEM_BUG_PATH.format(issue_id=bug_id)),
auth=(settings.BUG_TRACKING_SYSTEM_LOGIN,
settings.BUG_TRACKING_SYSTEM_PASSWORD),
headers={'Content-Type': 'application/json'})
data = response.json()
log.debug(data)
return data
53 changes: 13 additions & 40 deletions testreport/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

from testreport.models import Launch, FINISHED, STOPPED, CELERY_FINISHED_STATES
from testreport.models import Bug

from rest_framework.exceptions import APIException
import requests
from testreport.models import get_issue_fields_from_bts

import celery

Expand Down Expand Up @@ -102,7 +100,11 @@ def cleanup_database():
def update_bugs():
if settings.JIRA_INTEGRATION:
for bug in Bug.objects.all():
update_state(bug)
try:
update_state(bug)
except Exception as e:
log.error('Unable to update bug {}: {}'.
format(bug.externalId, e))
else:
log.info('Jira integration is off. '
'If you want to use this feature, turn it on.')
Expand All @@ -117,14 +119,16 @@ def update_state(bug):

if bug.state in settings.BUG_STATE_EXPIRED:
old_state = bug.state
new_state = _get_state_from_bts(bug)
new_state = \
get_issue_fields_from_bts(bug.externalId)['status']['name']
log.debug('Comparing bug state,'
'"{0}" and "{1}"'.format(old_state, new_state))
if old_state == new_state and diff > settings.BUG_TIME_EXPIRED:
if old_state == new_state and diff > float(settings.BUG_TIME_EXPIRED):
log.debug(
'Bug "{}" expired, deleting it from DB'.format(bug.externalId))
bug.delete()
elif old_state == new_state and diff < settings.BUG_TIME_EXPIRED:
elif old_state == new_state \
and diff < float(settings.BUG_TIME_EXPIRED):
log.debug(
'Bug "{}" not updated, '
'because {} seconds not expired'.format(
Expand All @@ -139,38 +143,7 @@ def update_state(bug):
log.debug("%s > %s time to update bug state.", diff,
settings.TIME_BEFORE_UPDATE_BUG_INFO)
bug.updated = now
bug.state = _get_state_from_bts(bug)
bug.state = \
get_issue_fields_from_bts(bug.externalId)['status']['name']
log.debug('Saving bug "{}"'.format(bug.externalId))
bug.save()


def get_name_from_bts(bug):
log.debug('Get name for bug "{}"'.format(bug.externalId))
return _get_bug(bug.externalId)['fields']['summary']


def _get_state_from_bts(bug):
log.debug('Get state for bug {}'.format(bug.externalId))
return _get_bug(bug.externalId)['fields']['status']['name']


def _get_bug(bug_id):
response = requests.get(
'https://{}{}'.format(
settings.BUG_TRACKING_SYSTEM_HOST,
settings.BUG_TRACKING_SYSTEM_BUG_PATH.format(issue_id=bug_id)),
auth=(settings.BUG_TRACKING_SYSTEM_LOGIN,
settings.BUG_TRACKING_SYSTEM_PASSWORD),
headers={'Content-Type': 'application/json'})
data = response.json()
log.debug(data)
errors = []
if 'errors' in data:
errors += data['errors']
if 'errorMessages' in data:
errors += data['errorMessages']
if len(errors) != 0:
errors = map(lambda x: x.encode('utf-8', errors='replace'), errors)
raise APIException(
"Bug tracking system: '{}'".format('\n'.join(errors)))
return data
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ setenv =
BROKER_URL=sqla+sqlite:///celerydb.sqlite
CDWS_WORKING_DIR=/tmp/cdws
DEBUG=False
JIRA_INTEGRATION = True
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
coveralls
Expand Down

0 comments on commit ccc65a2

Please sign in to comment.