Fix issue with task shortcodes
Part of the code assumed shortcodes were globally unique, and another part assumed the shortcodes are unique per project (the latter is correct). Now the project ID is taken from the URL the Subversion hook pushes to.
This commit is contained in:
@@ -22,51 +22,63 @@ SVN_SERVER_URL = 'svn://biserver/agent327'
|
||||
|
||||
logging.config.dictConfig(logging_config.LOGGING)
|
||||
|
||||
# Unfortunately, the svn module doesn't use classes, but uses in-function-defined
|
||||
# namedtuples instead. As a result, we can't import them, but have to recreate.
|
||||
LogEntry = collections.namedtuple('LogEntry', ['date', 'msg', 'revision', 'author', 'changelist'])
|
||||
|
||||
SVN_LOG_BATCH_1 = [
|
||||
LogEntry(date=datetime.datetime(2016, 4, 5, 10, 8, 5, 19211, tzinfo=tzutc()),
|
||||
msg='Initial commit', revision=43, author='fsiddi', changelist=None),
|
||||
LogEntry(date=datetime.datetime(2016, 4, 8, 13, 5, 39, 42537, tzinfo=tzutc()),
|
||||
msg='Initial commit of layout files', revision=44, author='hjalti', changelist=None),
|
||||
LogEntry(date=datetime.datetime(2016, 4, 8, 13, 6, 18, 947830, tzinfo=tzutc()),
|
||||
msg=None, revision=45, author='andy', changelist=None),
|
||||
LogEntry(date=datetime.datetime(2016, 4, 8, 14, 22, 24, 411916, tzinfo=tzutc()),
|
||||
msg="Add the eye lattices to the main group\n\nOtherwise when you link the agent group, those two lattices would be\nlinked as regular objects, and you'd need to move both proxy+lattices\nindividually.\n\n\n",
|
||||
revision=46, author='pablo', changelist=None),
|
||||
]
|
||||
|
||||
SVN_LOG_BATCH_2 = [
|
||||
LogEntry(date=datetime.datetime(2016, 4, 13, 17, 54, 50, 244305, tzinfo=tzutc()),
|
||||
msg='first initial agent model rework.', revision=47, author='andy', changelist=None),
|
||||
LogEntry(date=datetime.datetime(2016, 4, 14, 15, 57, 30, 951714, tzinfo=tzutc()),
|
||||
msg='third day of puching verts around', revision=48, author='andy', changelist=None),
|
||||
LogEntry(date=datetime.datetime(2016, 4, 21, 8, 21, 19, 390478, tzinfo=tzutc()),
|
||||
msg='last weeks edit. a couple of facial expression tests.\nstarting to modify the agent head heavily... W A R N I N G',
|
||||
revision=49, author='andy', changelist=None),
|
||||
LogEntry(date=datetime.datetime(2016, 4, 25, 9, 18, 17, 23841, tzinfo=tzutc()),
|
||||
msg='some expression tests.', revision=50, author='andy', changelist=None),
|
||||
LogEntry(date=datetime.datetime(2016, 4, 25, 10, 12, 23, 233796, tzinfo=tzutc()),
|
||||
msg='older version of the layout', revision=51, author='hjalti', changelist=None),
|
||||
]
|
||||
|
||||
SVN_LOG_BATCH_WITH_TASK_MARKERS = [
|
||||
LogEntry(date=datetime.datetime(2016, 4, 5, 10, 8, 5, 19211, tzinfo=tzutc()),
|
||||
msg='Initial commit', revision=1, author='fsiddi', changelist=None),
|
||||
LogEntry(date=datetime.datetime(2016, 4, 8, 13, 5, 39, 42537, tzinfo=tzutc()),
|
||||
msg='[T1234] modeled Hendrik IJzerbroot', revision=2, author='andy', changelist=None),
|
||||
LogEntry(date=datetime.datetime(2016, 4, 8, 13, 6, 18, 947830, tzinfo=tzutc()),
|
||||
msg='[T4415] scene layout, which also closes [T4433]', revision=3, author='hjalti',
|
||||
changelist=None),
|
||||
]
|
||||
|
||||
|
||||
class TestCommitLogObserver(unittest.TestCase):
|
||||
def setUp(self):
|
||||
from attract import subversion
|
||||
|
||||
self.pid1 = ObjectId(24 * 'a')
|
||||
self.pid2 = ObjectId(24 * 'b')
|
||||
|
||||
LogEntry = subversion.LogEntry
|
||||
self.SVN_LOG_BATCH_1 = [
|
||||
LogEntry(date=datetime.datetime(2016, 4, 5, 10, 8, 5, 19211, tzinfo=tzutc()),
|
||||
msg='Initial commit', revision=43, author='fsiddi', changelist=None,
|
||||
project_id=self.pid1),
|
||||
LogEntry(date=datetime.datetime(2016, 4, 8, 13, 5, 39, 42537, tzinfo=tzutc()),
|
||||
msg='Initial commit of layout files', revision=44, author='hjalti',
|
||||
changelist=None, project_id=self.pid1),
|
||||
LogEntry(date=datetime.datetime(2016, 4, 8, 13, 6, 18, 947830, tzinfo=tzutc()),
|
||||
msg=None, revision=45, author='andy', changelist=None, project_id=self.pid1),
|
||||
LogEntry(date=datetime.datetime(2016, 4, 8, 14, 22, 24, 411916, tzinfo=tzutc()),
|
||||
msg="Add the eye lattices to the main group\n\nOtherwise when you link the "
|
||||
"agent group, those two lattices would be\nlinked as regular objects, and "
|
||||
"you'd need to move both proxy+lattices\nindividually.\n\n\n",
|
||||
revision=46, author='pablo', changelist=None, project_id=self.pid1),
|
||||
]
|
||||
|
||||
self.SVN_LOG_BATCH_2 = [
|
||||
LogEntry(date=datetime.datetime(2016, 4, 13, 17, 54, 50, 244305, tzinfo=tzutc()),
|
||||
msg='first initial agent model rework.', revision=47, author='andy',
|
||||
changelist=None, project_id=self.pid1),
|
||||
LogEntry(date=datetime.datetime(2016, 4, 14, 15, 57, 30, 951714, tzinfo=tzutc()),
|
||||
msg='third day of puching verts around', revision=48, author='andy',
|
||||
changelist=None, project_id=self.pid1),
|
||||
LogEntry(date=datetime.datetime(2016, 4, 21, 8, 21, 19, 390478, tzinfo=tzutc()),
|
||||
msg='last weeks edit. a couple of facial expression tests.\nstarting to '
|
||||
'modify the agent head heavily... W A R N I N G',
|
||||
revision=49, author='andy', changelist=None, project_id=self.pid1),
|
||||
LogEntry(date=datetime.datetime(2016, 4, 25, 9, 18, 17, 23841, tzinfo=tzutc()),
|
||||
msg='some expression tests.', revision=50, author='andy', changelist=None,
|
||||
project_id=self.pid1),
|
||||
LogEntry(date=datetime.datetime(2016, 4, 25, 10, 12, 23, 233796, tzinfo=tzutc()),
|
||||
msg='older version of the layout', revision=51, author='hjalti',
|
||||
changelist=None, project_id=self.pid1),
|
||||
]
|
||||
|
||||
self.SVN_LOG_BATCH_WITH_TASK_MARKERS = [
|
||||
LogEntry(date=datetime.datetime(2016, 4, 5, 10, 8, 5, 19211, tzinfo=tzutc()),
|
||||
msg='Initial commit', revision=1, author='fsiddi', changelist=None,
|
||||
project_id=self.pid1),
|
||||
LogEntry(date=datetime.datetime(2016, 4, 8, 13, 5, 39, 42537, tzinfo=tzutc()),
|
||||
msg='[T1234] modeled Hendrik IJzerbroot', revision=2, author='andy',
|
||||
changelist=None, project_id=self.pid1),
|
||||
LogEntry(date=datetime.datetime(2016, 4, 8, 13, 6, 18, 947830, tzinfo=tzutc()),
|
||||
msg='[T4415] scene layout, which also closes [T4433]', revision=3,
|
||||
author='hjalti',
|
||||
changelist=None, project_id=ObjectId(24 * 'b')),
|
||||
]
|
||||
|
||||
self.client = subversion.obtain(SVN_SERVER_URL)
|
||||
# Passing in a real client to Mock() will ensure that isinstance() checks return True.
|
||||
self.mock_client = mock.Mock(self.client, name='svn_client')
|
||||
@@ -96,9 +108,9 @@ class TestCommitLogObserver(unittest.TestCase):
|
||||
self.mock_client.log_default = mock.Mock(name='log_default')
|
||||
self.mock_client.log_default.side_effect = [
|
||||
# First call, only four commits.
|
||||
SVN_LOG_BATCH_1,
|
||||
self.SVN_LOG_BATCH_1,
|
||||
# Second call, five commits.
|
||||
SVN_LOG_BATCH_2
|
||||
self.SVN_LOG_BATCH_2
|
||||
]
|
||||
|
||||
self.observer.last_seen_revision = 42
|
||||
@@ -116,7 +128,7 @@ class TestCommitLogObserver(unittest.TestCase):
|
||||
from attract import subversion
|
||||
|
||||
self.mock_client.log_default = mock.Mock(name='log_default',
|
||||
return_value=SVN_LOG_BATCH_WITH_TASK_MARKERS)
|
||||
return_value=self.SVN_LOG_BATCH_WITH_TASK_MARKERS)
|
||||
blinks = []
|
||||
|
||||
def record_blink(sender, **kwargs):
|
||||
@@ -128,12 +140,15 @@ class TestCommitLogObserver(unittest.TestCase):
|
||||
self.observer.fetch_and_observe()
|
||||
|
||||
self.assertEqual(3, len(blinks))
|
||||
self.assertEqual({'log_entry': SVN_LOG_BATCH_WITH_TASK_MARKERS[1], 'shortcode': 'T1234'},
|
||||
blinks[0])
|
||||
self.assertEqual({'log_entry': SVN_LOG_BATCH_WITH_TASK_MARKERS[2], 'shortcode': 'T4415'},
|
||||
blinks[1])
|
||||
self.assertEqual({'log_entry': SVN_LOG_BATCH_WITH_TASK_MARKERS[2], 'shortcode': 'T4433'},
|
||||
blinks[2])
|
||||
self.assertEqual(
|
||||
{'log_entry': self.SVN_LOG_BATCH_WITH_TASK_MARKERS[1], 'shortcode': 'T1234'},
|
||||
blinks[0])
|
||||
self.assertEqual(
|
||||
{'log_entry': self.SVN_LOG_BATCH_WITH_TASK_MARKERS[2], 'shortcode': 'T4415'},
|
||||
blinks[1])
|
||||
self.assertEqual(
|
||||
{'log_entry': self.SVN_LOG_BATCH_WITH_TASK_MARKERS[2], 'shortcode': 'T4433'},
|
||||
blinks[2])
|
||||
|
||||
def test_svn_error(self):
|
||||
"""SVN errors should not crash the observer."""
|
||||
@@ -158,13 +173,15 @@ class TestCommitLogObserver(unittest.TestCase):
|
||||
msg='Ünicøde is good',
|
||||
revision='123',
|
||||
author='børk',
|
||||
changelist='nothing')
|
||||
changelist='nothing',
|
||||
project_id=self.pid1)
|
||||
self.assertEqual(tuple(entry), (
|
||||
datetime.datetime(2016, 10, 21, 15, 40, 17, 0, tzinfo=tzutc()),
|
||||
'Ünicøde is good',
|
||||
'123',
|
||||
'børk',
|
||||
'nothing'
|
||||
'nothing',
|
||||
self.pid1,
|
||||
))
|
||||
|
||||
self.assertRaises(ValueError, subversion.create_log_entry,
|
||||
@@ -172,31 +189,36 @@ class TestCommitLogObserver(unittest.TestCase):
|
||||
msg='Ünicøde is good',
|
||||
revision='123',
|
||||
author='børk',
|
||||
changelist='nothing')
|
||||
changelist='nothing',
|
||||
project_id=self.pid1)
|
||||
|
||||
entry = subversion.create_log_entry(date_text='2016-10-21 17:40:17 +0200',
|
||||
msg='Ünicøde is good',
|
||||
revision='123',
|
||||
author='børk')
|
||||
author='børk',
|
||||
project_id=self.pid1)
|
||||
self.assertEqual(tuple(entry), (
|
||||
datetime.datetime(2016, 10, 21, 15, 40, 17, 0, tzinfo=tzutc()),
|
||||
'Ünicøde is good',
|
||||
'123',
|
||||
'børk',
|
||||
None
|
||||
None,
|
||||
self.pid1,
|
||||
))
|
||||
|
||||
entry = subversion.create_log_entry(
|
||||
date=datetime.datetime(2016, 10, 21, 15, 40, 17, 0, tzinfo=tzutc()),
|
||||
msg='Ünicøde is good',
|
||||
revision='123',
|
||||
author='børk')
|
||||
author='børk',
|
||||
project_id=self.pid1)
|
||||
self.assertEqual(tuple(entry), (
|
||||
datetime.datetime(2016, 10, 21, 15, 40, 17, 0, tzinfo=tzutc()),
|
||||
'Ünicøde is good',
|
||||
'123',
|
||||
'børk',
|
||||
None
|
||||
None,
|
||||
self.pid1,
|
||||
))
|
||||
|
||||
|
||||
@@ -238,6 +260,93 @@ class PushCommitTest(AbstractAttractTest):
|
||||
blinks[0]['log_entry'].msg)
|
||||
self.assertEqual(datetime.datetime(2016, 10, 21, 15, 40, 17, 0, tzinfo=tzutc()),
|
||||
blinks[0]['log_entry'].date)
|
||||
self.assertEqual(self.proj_id, blinks[0]['log_entry'].project_id)
|
||||
|
||||
def test_two_projects(self):
|
||||
from attract import cli, subversion
|
||||
|
||||
proj_id2, project2 = self.ensure_project_exists(project_overrides={
|
||||
'_id': ObjectId(24 * 'f'),
|
||||
'url': 'proj2',
|
||||
})
|
||||
|
||||
with self.app.test_request_context():
|
||||
_, token1 = cli.create_svner_account('svner1@example.com', self.project['url'])
|
||||
_, token2 = cli.create_svner_account('svner2@example.com', project2['url'])
|
||||
|
||||
blinks = []
|
||||
|
||||
def record_blink(sender, **kwargs):
|
||||
blinks.append(kwargs)
|
||||
|
||||
subversion.task_logged.connect(record_blink)
|
||||
|
||||
push_data = {
|
||||
'repo': 'strange-repo™',
|
||||
'revision': '4',
|
||||
'msg': 'မြန်မာဘာသာ is beautiful.\n\nThis solves task [T431134]',
|
||||
'author': 'Haha',
|
||||
'date': '2016-10-21 17:40:17 +0200',
|
||||
}
|
||||
self.post('/attract/api/%s/subversion/log' % self.project['url'],
|
||||
json=push_data,
|
||||
auth_token=token1['token'])
|
||||
self.post('/attract/api/%s/subversion/log' % project2['url'],
|
||||
json=push_data,
|
||||
auth_token=token2['token'])
|
||||
|
||||
self.assertEqual(2, len(blinks))
|
||||
|
||||
self.assertEqual('T431134', blinks[0]['shortcode'])
|
||||
self.assertEqual('မြန်မာဘာသာ is beautiful.\n\nThis solves task [T431134]',
|
||||
blinks[0]['log_entry'].msg)
|
||||
self.assertEqual(datetime.datetime(2016, 10, 21, 15, 40, 17, 0, tzinfo=tzutc()),
|
||||
blinks[0]['log_entry'].date)
|
||||
self.assertEqual(self.proj_id, blinks[0]['log_entry'].project_id)
|
||||
|
||||
self.assertEqual('T431134', blinks[1]['shortcode'])
|
||||
self.assertEqual('မြန်မာဘာသာ is beautiful.\n\nThis solves task [T431134]',
|
||||
blinks[1]['log_entry'].msg)
|
||||
self.assertEqual(datetime.datetime(2016, 10, 21, 15, 40, 17, 0, tzinfo=tzutc()),
|
||||
blinks[1]['log_entry'].date)
|
||||
self.assertEqual(proj_id2, blinks[1]['log_entry'].project_id)
|
||||
|
||||
def test_wrong_project(self):
|
||||
from attract import cli, subversion
|
||||
|
||||
proj_id2, project2 = self.ensure_project_exists(project_overrides={
|
||||
'_id': ObjectId(24 * 'f'),
|
||||
'url': 'proj2',
|
||||
})
|
||||
|
||||
with self.app.test_request_context():
|
||||
_, token1 = cli.create_svner_account('svner1@example.com', self.project['url'])
|
||||
_, token2 = cli.create_svner_account('svner2@example.com', project2['url'])
|
||||
|
||||
blinks = []
|
||||
|
||||
def record_blink(sender, **kwargs):
|
||||
blinks.append(kwargs)
|
||||
|
||||
subversion.task_logged.connect(record_blink)
|
||||
|
||||
push_data = {
|
||||
'repo': 'strange-repo™',
|
||||
'revision': '4',
|
||||
'msg': 'မြန်မာဘာသာ is beautiful.\n\nThis solves task [T431134]',
|
||||
'author': 'Haha',
|
||||
'date': '2016-10-21 17:40:17 +0200',
|
||||
}
|
||||
self.post('/attract/api/%s/subversion/log' % self.project['url'],
|
||||
json=push_data,
|
||||
auth_token=token2['token'],
|
||||
expected_status=403)
|
||||
self.post('/attract/api/%s/subversion/log' % project2['url'],
|
||||
json=push_data,
|
||||
auth_token=token1['token'],
|
||||
expected_status=403)
|
||||
|
||||
self.assertEqual(0, len(blinks))
|
||||
|
||||
|
||||
class SvnTaskLoggedTest(AbstractAttractTest):
|
||||
|
Reference in New Issue
Block a user