diff --git a/tools/lint-all b/tools/lint-all index 2e5e7898a0..f49b5b1f2d 100755 --- a/tools/lint-all +++ b/tools/lint-all @@ -145,6 +145,8 @@ def check_pyflakes(): 'redefinition of unused' in ln or ("zerver/models.py" in ln and " undefined name 'bugdown'" in ln) or + ("zerver/tests.py" in ln and + " unable to detect undefined names" in ln) or ("zerver/lib/tornado_ioloop_logging.py" in ln and "redefinition of function 'instrument_tornado_ioloop'" in ln) or ("zephyr_mirror_backend.py:" in ln and diff --git a/zerver/test_hooks.py b/zerver/test_hooks.py new file mode 100644 index 0000000000..98bae91c90 --- /dev/null +++ b/zerver/test_hooks.py @@ -0,0 +1,726 @@ +# -*- coding: utf-8 -*- +from zerver.lib.test_helpers import AuthedTestCase +from zerver.lib.test_runner import slow +from zerver.models import Message + +import ujson + +class JiraHookTests(AuthedTestCase): + + def send_jira_message(self, action): + email = "hamlet@zulip.com" + api_key = self.get_api_key(email) + url = "/api/v1/external/jira?api_key=%s" % (api_key,) + return self.send_json_payload(email, + url, + self.fixture_data('jira', action), + stream_name="jira", + content_type="application/json") + + def test_unknown(self): + email = "hamlet@zulip.com" + api_key = self.get_api_key(email) + url = "/api/v1/external/jira?api_key=%s" % (api_key,) + + result = self.client.post(url, self.fixture_data('jira', 'unknown'), + stream_name="jira", + content_type="application/json") + + self.assert_json_error(result, 'Unknown JIRA event type') + + def test_custom_stream(self): + email = "hamlet@zulip.com" + api_key = self.get_api_key(email) + action = 'created' + url = "/api/v1/external/jira?api_key=%s&stream=jira_custom" % (api_key,) + msg = self.send_json_payload(email, url, + self.fixture_data('jira', action), + stream_name="jira_custom", + content_type="application/json") + self.assertEqual(msg.subject, "BUG-15: New bug with hook") + self.assertEqual(msg.content, """Leo Franchi **created** [BUG-15](http://lfranchi.com:8080/browse/BUG-15) priority Major, assigned to **no one**: + +> New bug with hook""") + + def test_created(self): + msg = self.send_jira_message('created') + self.assertEqual(msg.subject, "BUG-15: New bug with hook") + self.assertEqual(msg.content, """Leo Franchi **created** [BUG-15](http://lfranchi.com:8080/browse/BUG-15) priority Major, assigned to **no one**: + +> New bug with hook""") + + def test_created_assignee(self): + msg = self.send_jira_message('created_assignee') + self.assertEqual(msg.subject, "TEST-4: Test Created Assignee") + self.assertEqual(msg.content, """Leonardo Franchi [Administrator] **created** [TEST-4](https://zulipp.atlassian.net/browse/TEST-4) priority Major, assigned to **Leonardo Franchi [Administrator]**: + +> Test Created Assignee""") + + def test_commented(self): + msg = self.send_jira_message('commented') + self.assertEqual(msg.subject, "BUG-15: New bug with hook") + self.assertEqual(msg.content, """Leo Franchi **updated** [BUG-15](http://lfranchi.com:8080/browse/BUG-15) (assigned to @**Othello, the Moor of Venice**): + + +Adding a comment. Oh, what a comment it is! +""") + + def test_commented_markup(self): + msg = self.send_jira_message('commented_markup') + self.assertEqual(msg.subject, "TEST-7: Testing of rich text") + self.assertEqual(msg.content, """Leonardo Franchi [Administrator] **updated** [TEST-7](https://zulipp.atlassian.net/browse/TEST-7):\n\n\nThis is a comment that likes to **exercise** a lot of _different_ `conventions` that `jira uses`.\r\n\r\n~~~\n\r\nthis code is not highlighted, but monospaced\r\n\n~~~\r\n\r\n~~~\n\r\ndef python():\r\n print "likes to be formatted"\r\n\n~~~\r\n\r\n[http://www.google.com](http://www.google.com) is a bare link, and [Google](http://www.google.com) is given a title.\r\n\r\nThanks!\r\n\r\n~~~ quote\n\r\nSomeone said somewhere\r\n\n~~~\n""") + + def test_deleted(self): + msg = self.send_jira_message('deleted') + self.assertEqual(msg.subject, "BUG-15: New bug with hook") + self.assertEqual(msg.content, "Leo Franchi **deleted** [BUG-15](http://lfranchi.com:8080/browse/BUG-15)!") + + def test_reassigned(self): + msg = self.send_jira_message('reassigned') + self.assertEqual(msg.subject, "BUG-15: New bug with hook") + self.assertEqual(msg.content, """Leo Franchi **updated** [BUG-15](http://lfranchi.com:8080/browse/BUG-15) (assigned to @**Othello, the Moor of Venice**): + +* Changed assignee from **None** to @**Othello, the Moor of Venice** +""") + + def test_reopened(self): + msg = self.send_jira_message('reopened') + self.assertEqual(msg.subject, "BUG-7: More cowbell polease") + self.assertEqual(msg.content, """Leo Franchi **updated** [BUG-7](http://lfranchi.com:8080/browse/BUG-7) (assigned to @**Othello, the Moor of Venice**): + +* Changed status from **Resolved** to **Reopened** + +Re-opened yeah! +""") + + def test_resolved(self): + msg = self.send_jira_message('resolved') + + self.assertEqual(msg.subject, "BUG-13: Refreshing the page loses the user's current posi...") + self.assertEqual(msg.content, """Leo Franchi **updated** [BUG-13](http://lfranchi.com:8080/browse/BUG-13) (assigned to @**Othello, the Moor of Venice**): + +* Changed status from **Open** to **Resolved** +* Changed assignee from **None** to @**Othello, the Moor of Venice** + +Fixed it, finally! +""") + + def test_workflow_postfuncion(self): + msg = self.send_jira_message('postfunction_hook') + + self.assertEqual(msg.subject, "TEST-5: PostTest") + self.assertEqual(msg.content, """Leo Franchi [Administrator] **transitioned** [TEST-5](https://lfranchi-test.atlassian.net/browse/TEST-5) from Resolved to Reopened""") + + def test_workflow_postfunction(self): + msg = self.send_jira_message('postfunction_hook') + + self.assertEqual(msg.subject, "TEST-5: PostTest") + self.assertEqual(msg.content, """Leo Franchi [Administrator] **transitioned** [TEST-5](https://lfranchi-test.atlassian.net/browse/TEST-5) from Resolved to Reopened""") + + def test_workflow_postfunction_started(self): + msg = self.send_jira_message('postfunction_started') + + self.assertEqual(msg.subject, "TEST-7: Gluttony of Post Functions") + self.assertEqual(msg.content, """Leo Franchi [Administrator] **transitioned** [TEST-7](https://lfranchi-test.atlassian.net/browse/TEST-7) from Open to Underway""") + + def test_workflow_postfunction_resolved(self): + msg = self.send_jira_message('postfunction_resolved') + + self.assertEqual(msg.subject, "TEST-7: Gluttony of Post Functions") + self.assertEqual(msg.content, """Leo Franchi [Administrator] **transitioned** [TEST-7](https://lfranchi-test.atlassian.net/browse/TEST-7) from Open to Resolved""") + + def test_mention(self): + msg = self.send_jira_message('watch_mention_updated') + self.assertEqual(msg.subject, "TEST-5: Lunch Decision Needed") + self.assertEqual(msg.content, """Leonardo Franchi [Administrator] **updated** [TEST-5](https://zulipp.atlassian.net/browse/TEST-5) (assigned to @**Othello, the Moor of Venice**): + + +Making a comment, @**Othello, the Moor of Venice** is watching this issue +""") + +class BeanstalkHookTests(AuthedTestCase): + def send_beanstalk_message(self, action): + email = "hamlet@zulip.com" + data = {'payload': self.fixture_data('beanstalk', action)} + return self.send_json_payload(email, "/api/v1/external/beanstalk", + data, + stream_name="commits", + **self.api_auth(email)) + + def test_git_single(self): + msg = self.send_beanstalk_message('git_singlecommit') + self.assertEqual(msg.subject, "work-test") + self.assertEqual(msg.content, """Leo Franchi [pushed](http://lfranchi-svn.beanstalkapp.com/work-test) to branch master + +* [e50508d](http://lfranchi-svn.beanstalkapp.com/work-test/changesets/e50508df): add some stuff +""") + + @slow(0.20, "lots of queries") + def test_git_multiple(self): + msg = self.send_beanstalk_message('git_multiple') + self.assertEqual(msg.subject, "work-test") + self.assertEqual(msg.content, """Leo Franchi [pushed](http://lfranchi-svn.beanstalkapp.com/work-test) to branch master + +* [edf529c](http://lfranchi-svn.beanstalkapp.com/work-test/changesets/edf529c7): Added new file +* [c2a191b](http://lfranchi-svn.beanstalkapp.com/work-test/changesets/c2a191b9): Filled in new file with some stuff +* [2009815](http://lfranchi-svn.beanstalkapp.com/work-test/changesets/20098158): More work to fix some bugs +""") + + def test_svn_addremove(self): + msg = self.send_beanstalk_message('svn_addremove') + self.assertEqual(msg.subject, "svn r3") + self.assertEqual(msg.content, """Leo Franchi pushed [revision 3](http://lfranchi-svn.beanstalkapp.com/work-test/changesets/3): + +> Removed a file and added another one!""") + + def test_svn_changefile(self): + msg = self.send_beanstalk_message('svn_changefile') + self.assertEqual(msg.subject, "svn r2") + self.assertEqual(msg.content, """Leo Franchi pushed [revision 2](http://lfranchi-svn.beanstalkapp.com/work-test/changesets/2): + +> Added some code""") + +class GithubV1HookTests(AuthedTestCase): + + push_content = """zbenjamin [pushed](https://github.com/zbenjamin/zulip-test/compare/4f9adc4777d5...b95449196980) to branch master + +* [48c329a](https://github.com/zbenjamin/zulip-test/commit/48c329a0b68a9a379ff195ee3f1c1f4ab0b2a89e): Add baz +* [06ebe5f](https://github.com/zbenjamin/zulip-test/commit/06ebe5f472a32f6f31fd2a665f0c7442b69cce72): Baz needs to be longer +* [b954491](https://github.com/zbenjamin/zulip-test/commit/b95449196980507f08209bdfdc4f1d611689b7a8): Final edit to baz, I swear +""" + + def test_spam_branch_is_ignored(self): + email = "hamlet@zulip.com" + api_key = self.get_api_key(email) + stream = 'commits' + data = ujson.loads(self.fixture_data('github', 'v1_push')) + data.update({'email': email, + 'api-key': api_key, + 'branches': 'dev,staging', + 'stream': stream, + 'payload': ujson.dumps(data['payload'])}) + url = '/api/v1/external/github' + + # We subscribe to the stream in this test, even though + # it won't get written, to avoid failing for the wrong + # reason. + self.subscribe_to_stream(email, stream) + + prior_count = Message.objects.count() + + result = self.client.post(url, data) + self.assert_json_success(result) + + after_count = Message.objects.count() + self.assertEqual(prior_count, after_count) + + + def basic_test(self, fixture_name, stream_name, expected_subject, expected_content, send_stream=False, branches=None): + email = "hamlet@zulip.com" + api_key = self.get_api_key(email) + data = ujson.loads(self.fixture_data('github', 'v1_' + fixture_name)) + data.update({'email': email, + 'api-key': api_key, + 'payload': ujson.dumps(data['payload'])}) + if send_stream: + data['stream'] = stream_name + if branches is not None: + data['branches'] = branches + msg = self.send_json_payload(email, "/api/v1/external/github", + data, + stream_name=stream_name) + self.assertEqual(msg.subject, expected_subject) + self.assertEqual(msg.content, expected_content) + + def test_user_specified_branches(self): + self.basic_test('push', 'my_commits', 'zulip-test', self.push_content, + send_stream=True, branches="master,staging") + + def test_user_specified_stream(self): + # Around May 2013 the github webhook started to specify the stream. + # Before then, the stream was hard coded to "commits". + self.basic_test('push', 'my_commits', 'zulip-test', self.push_content, + send_stream=True) + + def test_legacy_hook(self): + self.basic_test('push', 'commits', 'zulip-test', self.push_content) + + def test_issues_opened(self): + self.basic_test('issues_opened', 'issues', + "zulip-test: issue 5: The frobnicator doesn't work", + "zbenjamin opened [issue 5](https://github.com/zbenjamin/zulip-test/issues/5)\n\n~~~ quote\nI tried changing the widgets, but I got:\r\n\r\nPermission denied: widgets are immutable\n~~~") + + def test_issue_comment(self): + self.basic_test('issue_comment', 'issues', + "zulip-test: issue 5: The frobnicator doesn't work", + "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/issues/5#issuecomment-23374280) on [issue 5](https://github.com/zbenjamin/zulip-test/issues/5)\n\n~~~ quote\nWhoops, I did something wrong.\r\n\r\nI'm sorry.\n~~~") + + def test_issues_closed(self): + self.basic_test('issues_closed', 'issues', + "zulip-test: issue 5: The frobnicator doesn't work", + "zbenjamin closed [issue 5](https://github.com/zbenjamin/zulip-test/issues/5)") + + def test_pull_request_opened(self): + self.basic_test('pull_request_opened', 'commits', + "zulip-test: pull request 7: Counting is hard.", + "lfaraone opened [pull request 7](https://github.com/zbenjamin/zulip-test/pull/7)\n\n~~~ quote\nOmitted something I think?\n~~~") + + def test_pull_request_closed(self): + self.basic_test('pull_request_closed', 'commits', + "zulip-test: pull request 7: Counting is hard.", + "zbenjamin closed [pull request 7](https://github.com/zbenjamin/zulip-test/pull/7)") + + def test_pull_request_synchronize(self): + self.basic_test('pull_request_synchronize', 'commits', + "zulip-test: pull request 13: Even more cowbell.", + "zbenjamin synchronized [pull request 13](https://github.com/zbenjamin/zulip-test/pull/13)") + + def test_pull_request_comment(self): + self.basic_test('pull_request_comment', 'commits', + "zulip-test: pull request 9: Less cowbell.", + "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/pull/9#issuecomment-24771110) on [pull request 9](https://github.com/zbenjamin/zulip-test/pull/9)\n\n~~~ quote\nYeah, who really needs more cowbell than we already have?\n~~~") + + def test_pull_request_comment_user_specified_stream(self): + self.basic_test('pull_request_comment', 'my_commits', + "zulip-test: pull request 9: Less cowbell.", + "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/pull/9#issuecomment-24771110) on [pull request 9](https://github.com/zbenjamin/zulip-test/pull/9)\n\n~~~ quote\nYeah, who really needs more cowbell than we already have?\n~~~", + send_stream=True) + + def test_commit_comment(self): + self.basic_test('commit_comment', 'commits', + "zulip-test: commit 7c994678d2f98797d299abed852d3ff9d0834533", + "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/commit/7c994678d2f98797d299abed852d3ff9d0834533#commitcomment-4252302)\n\n~~~ quote\nAre we sure this is enough cowbell?\n~~~") + + def test_commit_comment_line(self): + self.basic_test('commit_comment_line', 'commits', + "zulip-test: commit 7c994678d2f98797d299abed852d3ff9d0834533", + "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/commit/7c994678d2f98797d299abed852d3ff9d0834533#commitcomment-4252307) on `cowbell`, line 13\n\n~~~ quote\nThis line adds /unlucky/ cowbell (because of its line number). We should remove it.\n~~~") + +class GithubV2HookTests(AuthedTestCase): + + push_content = """zbenjamin [pushed](https://github.com/zbenjamin/zulip-test/compare/4f9adc4777d5...b95449196980) to branch master + +* [48c329a](https://github.com/zbenjamin/zulip-test/commit/48c329a0b68a9a379ff195ee3f1c1f4ab0b2a89e): Add baz +* [06ebe5f](https://github.com/zbenjamin/zulip-test/commit/06ebe5f472a32f6f31fd2a665f0c7442b69cce72): Baz needs to be longer +* [b954491](https://github.com/zbenjamin/zulip-test/commit/b95449196980507f08209bdfdc4f1d611689b7a8): Final edit to baz, I swear +""" + + def test_spam_branch_is_ignored(self): + email = "hamlet@zulip.com" + api_key = self.get_api_key(email) + stream = 'commits' + data = ujson.loads(self.fixture_data('github', 'v2_push')) + data.update({'email': email, + 'api-key': api_key, + 'branches': 'dev,staging', + 'stream': stream, + 'payload': ujson.dumps(data['payload'])}) + url = '/api/v1/external/github' + + # We subscribe to the stream in this test, even though + # it won't get written, to avoid failing for the wrong + # reason. + self.subscribe_to_stream(email, stream) + + prior_count = Message.objects.count() + + result = self.client.post(url, data) + self.assert_json_success(result) + + after_count = Message.objects.count() + self.assertEqual(prior_count, after_count) + + + def basic_test(self, fixture_name, stream_name, expected_subject, expected_content, send_stream=False, branches=None): + email = "hamlet@zulip.com" + api_key = self.get_api_key(email) + data = ujson.loads(self.fixture_data('github', 'v2_' + fixture_name)) + data.update({'email': email, + 'api-key': api_key, + 'payload': ujson.dumps(data['payload'])}) + if send_stream: + data['stream'] = stream_name + if branches is not None: + data['branches'] = branches + msg = self.send_json_payload(email, "/api/v1/external/github", + data, + stream_name=stream_name) + self.assertEqual(msg.subject, expected_subject) + self.assertEqual(msg.content, expected_content) + + def test_user_specified_branches(self): + self.basic_test('push', 'my_commits', 'zulip-test', self.push_content, + send_stream=True, branches="master,staging") + + def test_user_specified_stream(self): + # Around May 2013 the github webhook started to specify the stream. + # Before then, the stream was hard coded to "commits". + self.basic_test('push', 'my_commits', 'zulip-test', self.push_content, + send_stream=True) + + def test_legacy_hook(self): + self.basic_test('push', 'commits', 'zulip-test', self.push_content) + + def test_issues_opened(self): + self.basic_test('issues_opened', 'issues', + "zulip-test: issue 5: The frobnicator doesn't work", + "zbenjamin opened [issue 5](https://github.com/zbenjamin/zulip-test/issues/5)\n\n~~~ quote\nI tried changing the widgets, but I got:\r\n\r\nPermission denied: widgets are immutable\n~~~") + + def test_issue_comment(self): + self.basic_test('issue_comment', 'issues', + "zulip-test: issue 5: The frobnicator doesn't work", + "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/issues/5#issuecomment-23374280) on [issue 5](https://github.com/zbenjamin/zulip-test/issues/5)\n\n~~~ quote\nWhoops, I did something wrong.\r\n\r\nI'm sorry.\n~~~") + + def test_issues_closed(self): + self.basic_test('issues_closed', 'issues', + "zulip-test: issue 5: The frobnicator doesn't work", + "zbenjamin closed [issue 5](https://github.com/zbenjamin/zulip-test/issues/5)") + + def test_pull_request_opened(self): + self.basic_test('pull_request_opened', 'commits', + "zulip-test: pull request 7: Counting is hard.", + "lfaraone opened [pull request 7](https://github.com/zbenjamin/zulip-test/pull/7)\n\n~~~ quote\nOmitted something I think?\n~~~") + + def test_pull_request_closed(self): + self.basic_test('pull_request_closed', 'commits', + "zulip-test: pull request 7: Counting is hard.", + "zbenjamin closed [pull request 7](https://github.com/zbenjamin/zulip-test/pull/7)") + + def test_pull_request_synchronize(self): + self.basic_test('pull_request_synchronize', 'commits', + "zulip-test: pull request 13: Even more cowbell.", + "zbenjamin synchronized [pull request 13](https://github.com/zbenjamin/zulip-test/pull/13)") + + def test_pull_request_comment(self): + self.basic_test('pull_request_comment', 'commits', + "zulip-test: pull request 9: Less cowbell.", + "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/pull/9#issuecomment-24771110) on [pull request 9](https://github.com/zbenjamin/zulip-test/pull/9)\n\n~~~ quote\nYeah, who really needs more cowbell than we already have?\n~~~") + + def test_pull_request_comment_user_specified_stream(self): + self.basic_test('pull_request_comment', 'my_commits', + "zulip-test: pull request 9: Less cowbell.", + "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/pull/9#issuecomment-24771110) on [pull request 9](https://github.com/zbenjamin/zulip-test/pull/9)\n\n~~~ quote\nYeah, who really needs more cowbell than we already have?\n~~~", + send_stream=True) + + def test_commit_comment(self): + self.basic_test('commit_comment', 'commits', + "zulip-test: commit 7c994678d2f98797d299abed852d3ff9d0834533", + "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/commit/7c994678d2f98797d299abed852d3ff9d0834533#commitcomment-4252302)\n\n~~~ quote\nAre we sure this is enough cowbell?\n~~~") + + def test_commit_comment_line(self): + self.basic_test('commit_comment_line', 'commits', + "zulip-test: commit 7c994678d2f98797d299abed852d3ff9d0834533", + "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/commit/7c994678d2f98797d299abed852d3ff9d0834533#commitcomment-4252307) on `cowbell`, line 13\n\n~~~ quote\nThis line adds /unlucky/ cowbell (because of its line number). We should remove it.\n~~~") + +class PivotalV3HookTests(AuthedTestCase): + + def send_pivotal_message(self, name): + email = "hamlet@zulip.com" + api_key = self.get_api_key(email) + return self.send_json_payload(email, "/api/v1/external/pivotal?api_key=%s&stream=%s" % (api_key,"pivotal"), + self.fixture_data('pivotal', name, file_type='xml'), + stream_name="pivotal", + content_type="application/xml") + + def test_accepted(self): + msg = self.send_pivotal_message('accepted') + self.assertEqual(msg.subject, 'My new Feature story') + self.assertEqual(msg.content, 'Leo Franchi accepted "My new Feature story" \ +[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48276573)') + + def test_commented(self): + msg = self.send_pivotal_message('commented') + self.assertEqual(msg.subject, 'Comment added') + self.assertEqual(msg.content, 'Leo Franchi added comment: "FIX THIS NOW" \ +[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48276573)') + + def test_created(self): + msg = self.send_pivotal_message('created') + self.assertEqual(msg.subject, 'My new Feature story') + self.assertEqual(msg.content, 'Leo Franchi added "My new Feature story" \ +(unscheduled feature):\n\n~~~ quote\nThis is my long description\n~~~\n\n \ +[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48276573)') + + def test_delivered(self): + msg = self.send_pivotal_message('delivered') + self.assertEqual(msg.subject, 'Another new story') + self.assertEqual(msg.content, 'Leo Franchi delivered "Another new story" \ +[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48278289)') + + def test_finished(self): + msg = self.send_pivotal_message('finished') + self.assertEqual(msg.subject, 'Another new story') + self.assertEqual(msg.content, 'Leo Franchi finished "Another new story" \ +[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48278289)') + + def test_moved(self): + msg = self.send_pivotal_message('moved') + self.assertEqual(msg.subject, 'My new Feature story') + self.assertEqual(msg.content, 'Leo Franchi edited "My new Feature story" \ +[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48276573)') + + def test_rejected(self): + msg = self.send_pivotal_message('rejected') + self.assertEqual(msg.subject, 'Another new story') + self.assertEqual(msg.content, 'Leo Franchi rejected "Another new story" with comments: \ +"Not good enough, sorry" [(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48278289)') + + def test_started(self): + msg = self.send_pivotal_message('started') + self.assertEqual(msg.subject, 'Another new story') + self.assertEqual(msg.content, 'Leo Franchi started "Another new story" \ +[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48278289)') + + def test_created_estimate(self): + msg = self.send_pivotal_message('created_estimate') + self.assertEqual(msg.subject, 'Another new story') + self.assertEqual(msg.content, 'Leo Franchi added "Another new story" \ +(unscheduled feature worth 2 story points):\n\n~~~ quote\nSome loong description\n~~~\n\n \ +[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48278289)') + + def test_type_changed(self): + msg = self.send_pivotal_message('type_changed') + self.assertEqual(msg.subject, 'My new Feature story') + self.assertEqual(msg.content, 'Leo Franchi edited "My new Feature story" \ +[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48276573)') + +class PivotalV5HookTests(AuthedTestCase): + def send_pivotal_message(self, name): + email = "hamlet@zulip.com" + api_key = self.get_api_key(email) + return self.send_json_payload(email, "/api/v1/external/pivotal?api_key=%s&stream=%s" % (api_key,"pivotal"), + self.fixture_data('pivotal', "v5_" + name, file_type='json'), + stream_name="pivotal", + content_type="application/xml") + + def test_accepted(self): + msg = self.send_pivotal_message('accepted') + self.assertEqual(msg.subject, '#63486316: Story of the Year') + self.assertEqual(msg.content, """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Story of the Year](http://www.pivotaltracker.com/story/show/63486316): +* state changed from **unstarted** to **accepted** +""") + + def test_commented(self): + msg = self.send_pivotal_message('commented') + self.assertEqual(msg.subject, '#63486316: Story of the Year') + self.assertEqual(msg.content, """Leo Franchi added a comment to [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Story of the Year](http://www.pivotaltracker.com/story/show/63486316): +~~~quote +A comment on the story +~~~""") + + def test_created(self): + msg = self.send_pivotal_message('created') + self.assertEqual(msg.subject, '#63495662: Story that I created') + self.assertEqual(msg.content, """Leo Franchi created bug: [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Story that I created](http://www.pivotaltracker.com/story/show/63495662) +* State is **unscheduled** +* Description is + +> What a description""") + + def test_delivered(self): + msg = self.send_pivotal_message('delivered') + self.assertEqual(msg.subject, '#63486316: Story of the Year') + self.assertEqual(msg.content, """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Story of the Year](http://www.pivotaltracker.com/story/show/63486316): +* state changed from **accepted** to **delivered** +""") + + def test_finished(self): + msg = self.send_pivotal_message('finished') + self.assertEqual(msg.subject, '#63486316: Story of the Year') + self.assertEqual(msg.content, """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Story of the Year](http://www.pivotaltracker.com/story/show/63486316): +* state changed from **delivered** to **accepted** +""") + + def test_moved(self): + msg = self.send_pivotal_message('moved') + self.assertEqual(msg.subject, '#63496066: Pivotal Test') + self.assertEqual(msg.content, """Leo Franchi moved [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Pivotal Test](http://www.pivotaltracker.com/story/show/63496066) from **unstarted** to **unscheduled**""") + + def test_rejected(self): + msg = self.send_pivotal_message('rejected') + self.assertEqual(msg.subject, '#63486316: Story of the Year') + self.assertEqual(msg.content, """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Story of the Year](http://www.pivotaltracker.com/story/show/63486316): +* Comment added: +~~~quote +Try again next time +~~~ +* state changed from **delivered** to **rejected** +""") + + def test_started(self): + msg = self.send_pivotal_message('started') + self.assertEqual(msg.subject, '#63495972: Fresh Story') + self.assertEqual(msg.content, """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Fresh Story](http://www.pivotaltracker.com/story/show/63495972): +* state changed from **unstarted** to **started** +""") + + def test_created_estimate(self): + msg = self.send_pivotal_message('created_estimate') + self.assertEqual(msg.subject, '#63496066: Pivotal Test') + self.assertEqual(msg.content, """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Pivotal Test](http://www.pivotaltracker.com/story/show/63496066): +* estimate is now **3 points** +""") + + def test_type_changed(self): + msg = self.send_pivotal_message('type_changed') + self.assertEqual(msg.subject, '#63496066: Pivotal Test') + self.assertEqual(msg.content, """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Pivotal Test](http://www.pivotaltracker.com/story/show/63496066): +* estimate changed from 3 to **0 points** +* type changed from **feature** to **bug** +""") + +class NewRelicHookTests(AuthedTestCase): + def send_new_relic_message(self, name): + email = "hamlet@zulip.com" + api_key = self.get_api_key(email) + return self.send_json_payload(email, "/api/v1/external/newrelic?api_key=%s&stream=%s" % (api_key,"newrelic"), + self.fixture_data('newrelic', name, file_type='txt'), + stream_name="newrelic", + content_type="application/x-www-form-urlencoded") + + def test_alert(self): + msg = self.send_new_relic_message('alert') + self.assertEqual(msg.subject, "Apdex score fell below critical level of 0.90") + self.assertEqual(msg.content, 'Alert opened on [application name]: \ +Apdex score fell below critical level of 0.90\n\ +[View alert](https://rpm.newrelc.com/accounts/[account_id]/applications/[application_id]/incidents/[incident_id])') + + def test_deployment(self): + msg = self.send_new_relic_message('deployment') + self.assertEqual(msg.subject, 'Test App deploy') + self.assertEqual(msg.content, '`1242` deployed by **Zulip Test**\n\ +Description sent via curl\n\nChangelog string') + +class StashHookTests(AuthedTestCase): + def test_stash_message(self): + """ + Messages are generated by Stash on a `git push`. + + The subject describes the repo and Stash "project". The + content describes the commits pushed. + """ + email = "hamlet@zulip.com" + msg = self.send_json_payload( + email, "/api/v1/external/stash?stream=commits", + self.fixture_data("stash", "push", file_type="json"), + stream_name="commits", + content_type="application/x-www-form-urlencoded", + **self.api_auth(email)) + + self.assertEqual(msg.subject, u"Secret project/Operation unicorn: master") + self.assertEqual(msg.content, """`f259e90` was pushed to **master** in **Secret project/Operation unicorn** with: + +* `f259e90`: Updating poms ...""") + +class FreshdeskHookTests(AuthedTestCase): + def generate_webhook_response(self, fixture): + """ + Helper function to handle the webhook boilerplate. + """ + email = "hamlet@zulip.com" + return self.send_json_payload( + email, "/api/v1/external/freshdesk?stream=freshdesk", + self.fixture_data("freshdesk", fixture, file_type="json"), + stream_name="freshdesk", + content_type="application/x-www-form-urlencoded", + **self.api_auth(email)) + + def test_ticket_creation(self): + """ + Messages are generated on ticket creation through Freshdesk's + "Dispatch'r" service. + """ + msg = self.generate_webhook_response("ticket_created") + self.assertEqual(msg.subject, u"#11: Test ticket subject ☃") + self.assertEqual(msg.content, u"""Requester ☃ Bob created [ticket #11](http://test1234zzz.freshdesk.com/helpdesk/tickets/11): + +~~~ quote +Test ticket description ☃. +~~~ + +Type: **Incident** +Priority: **High** +Status: **Pending**""") + + def test_status_change(self): + """ + Messages are generated when a ticket's status changes through + Freshdesk's "Observer" service. + """ + msg = self.generate_webhook_response("status_changed") + self.assertEqual(msg.subject, u"#11: Test ticket subject ☃") + self.assertEqual(msg.content, """Requester Bob updated [ticket #11](http://test1234zzz.freshdesk.com/helpdesk/tickets/11): + +Status: **Resolved** => **Waiting on Customer**""") + + def test_priority_change(self): + """ + Messages are generated when a ticket's priority changes through + Freshdesk's "Observer" service. + """ + msg = self.generate_webhook_response("priority_changed") + self.assertEqual(msg.subject, u"#11: Test ticket subject") + self.assertEqual(msg.content, """Requester Bob updated [ticket #11](http://test1234zzz.freshdesk.com/helpdesk/tickets/11): + +Priority: **High** => **Low**""") + + def note_change(self, fixture, note_type): + """ + Messages are generated when a note gets added to a ticket through + Freshdesk's "Observer" service. + """ + msg = self.generate_webhook_response(fixture) + self.assertEqual(msg.subject, u"#11: Test ticket subject") + self.assertEqual(msg.content, """Requester Bob added a %s note to [ticket #11](http://test1234zzz.freshdesk.com/helpdesk/tickets/11).""" % (note_type,)) + + def test_private_note_change(self): + self.note_change("private_note", "private") + + def test_public_note_change(self): + self.note_change("public_note", "public") + + def test_inline_image(self): + """ + Freshdesk sends us descriptions as HTML, so we have to make the + descriptions Zulip markdown-friendly while still doing our best to + preserve links and images. + """ + msg = self.generate_webhook_response("inline_images") + self.assertEqual(msg.subject, u"#12: Not enough ☃ guinea pigs") + self.assertIn("[guinea_pig.png](http://cdn.freshdesk.com/data/helpdesk/attachments/production/12744808/original/guinea_pig.png)", msg.content) + +class ZenDeskHookTests(AuthedTestCase): + + def generate_webhook_response(self, ticket_title='User can\'t login', + ticket_id=54, message='Message', + stream_name='zendesk'): + data = { + 'ticket_title': ticket_title, + 'ticket_id': ticket_id, + 'message': message, + 'stream': stream_name, + } + email = 'hamlet@zulip.com' + self.subscribe_to_stream(email, stream_name) + result = self.client.post('/api/v1/external/zendesk', data, + **self.api_auth(email)) + self.assert_json_success(result) + + # Check the correct message was sent + msg = Message.objects.filter().order_by('-id')[0] + self.assertEqual(msg.sender.email, email) + + return msg + + def test_subject(self): + msg = self.generate_webhook_response(ticket_id=4, ticket_title="Test ticket") + self.assertEqual(msg.subject, '#4: Test ticket') + + def test_long_subject(self): + msg = self.generate_webhook_response(ticket_id=4, ticket_title="Test ticket" + '!' * 80) + self.assertEqual(msg.subject, '#4: Test ticket' + '!' * 42 + '...') + + def test_content(self): + msg = self.generate_webhook_response(message='New comment:\n> It is better\n* here') + self.assertEqual(msg.content, 'New comment:\n> It is better\n* here') + diff --git a/zerver/tests.py b/zerver/tests.py index 726bfe6af2..f6ea344c63 100644 --- a/zerver/tests.py +++ b/zerver/tests.py @@ -1,6 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import +# This is less than ideal, but I couldn't figure out Django's extremely +# opaque test runner. We want to split out tests into different files, +# but it would be even better if we could run the files individually. +from zerver.test_hooks import * # noqa + from django.test import TestCase from django.utils.timezone import now from django.core.exceptions import ValidationError @@ -4625,725 +4630,6 @@ class StarTests(AuthedTestCase): self.assertEqual(sent_message.message.content, content) self.assertFalse(sent_message.flags.starred) -class JiraHookTests(AuthedTestCase): - - def send_jira_message(self, action): - email = "hamlet@zulip.com" - api_key = self.get_api_key(email) - url = "/api/v1/external/jira?api_key=%s" % (api_key,) - return self.send_json_payload(email, - url, - self.fixture_data('jira', action), - stream_name="jira", - content_type="application/json") - - def test_unknown(self): - email = "hamlet@zulip.com" - api_key = self.get_api_key(email) - url = "/api/v1/external/jira?api_key=%s" % (api_key,) - - result = self.client.post(url, self.fixture_data('jira', 'unknown'), - stream_name="jira", - content_type="application/json") - - self.assert_json_error(result, 'Unknown JIRA event type') - - def test_custom_stream(self): - email = "hamlet@zulip.com" - api_key = self.get_api_key(email) - action = 'created' - url = "/api/v1/external/jira?api_key=%s&stream=jira_custom" % (api_key,) - msg = self.send_json_payload(email, url, - self.fixture_data('jira', action), - stream_name="jira_custom", - content_type="application/json") - self.assertEqual(msg.subject, "BUG-15: New bug with hook") - self.assertEqual(msg.content, """Leo Franchi **created** [BUG-15](http://lfranchi.com:8080/browse/BUG-15) priority Major, assigned to **no one**: - -> New bug with hook""") - - def test_created(self): - msg = self.send_jira_message('created') - self.assertEqual(msg.subject, "BUG-15: New bug with hook") - self.assertEqual(msg.content, """Leo Franchi **created** [BUG-15](http://lfranchi.com:8080/browse/BUG-15) priority Major, assigned to **no one**: - -> New bug with hook""") - - def test_created_assignee(self): - msg = self.send_jira_message('created_assignee') - self.assertEqual(msg.subject, "TEST-4: Test Created Assignee") - self.assertEqual(msg.content, """Leonardo Franchi [Administrator] **created** [TEST-4](https://zulipp.atlassian.net/browse/TEST-4) priority Major, assigned to **Leonardo Franchi [Administrator]**: - -> Test Created Assignee""") - - def test_commented(self): - msg = self.send_jira_message('commented') - self.assertEqual(msg.subject, "BUG-15: New bug with hook") - self.assertEqual(msg.content, """Leo Franchi **updated** [BUG-15](http://lfranchi.com:8080/browse/BUG-15) (assigned to @**Othello, the Moor of Venice**): - - -Adding a comment. Oh, what a comment it is! -""") - - def test_commented_markup(self): - msg = self.send_jira_message('commented_markup') - self.assertEqual(msg.subject, "TEST-7: Testing of rich text") - self.assertEqual(msg.content, """Leonardo Franchi [Administrator] **updated** [TEST-7](https://zulipp.atlassian.net/browse/TEST-7):\n\n\nThis is a comment that likes to **exercise** a lot of _different_ `conventions` that `jira uses`.\r\n\r\n~~~\n\r\nthis code is not highlighted, but monospaced\r\n\n~~~\r\n\r\n~~~\n\r\ndef python():\r\n print "likes to be formatted"\r\n\n~~~\r\n\r\n[http://www.google.com](http://www.google.com) is a bare link, and [Google](http://www.google.com) is given a title.\r\n\r\nThanks!\r\n\r\n~~~ quote\n\r\nSomeone said somewhere\r\n\n~~~\n""") - - def test_deleted(self): - msg = self.send_jira_message('deleted') - self.assertEqual(msg.subject, "BUG-15: New bug with hook") - self.assertEqual(msg.content, "Leo Franchi **deleted** [BUG-15](http://lfranchi.com:8080/browse/BUG-15)!") - - def test_reassigned(self): - msg = self.send_jira_message('reassigned') - self.assertEqual(msg.subject, "BUG-15: New bug with hook") - self.assertEqual(msg.content, """Leo Franchi **updated** [BUG-15](http://lfranchi.com:8080/browse/BUG-15) (assigned to @**Othello, the Moor of Venice**): - -* Changed assignee from **None** to @**Othello, the Moor of Venice** -""") - - def test_reopened(self): - msg = self.send_jira_message('reopened') - self.assertEqual(msg.subject, "BUG-7: More cowbell polease") - self.assertEqual(msg.content, """Leo Franchi **updated** [BUG-7](http://lfranchi.com:8080/browse/BUG-7) (assigned to @**Othello, the Moor of Venice**): - -* Changed status from **Resolved** to **Reopened** - -Re-opened yeah! -""") - - def test_resolved(self): - msg = self.send_jira_message('resolved') - - self.assertEqual(msg.subject, "BUG-13: Refreshing the page loses the user's current posi...") - self.assertEqual(msg.content, """Leo Franchi **updated** [BUG-13](http://lfranchi.com:8080/browse/BUG-13) (assigned to @**Othello, the Moor of Venice**): - -* Changed status from **Open** to **Resolved** -* Changed assignee from **None** to @**Othello, the Moor of Venice** - -Fixed it, finally! -""") - - def test_workflow_postfuncion(self): - msg = self.send_jira_message('postfunction_hook') - - self.assertEqual(msg.subject, "TEST-5: PostTest") - self.assertEqual(msg.content, """Leo Franchi [Administrator] **transitioned** [TEST-5](https://lfranchi-test.atlassian.net/browse/TEST-5) from Resolved to Reopened""") - - def test_workflow_postfunction(self): - msg = self.send_jira_message('postfunction_hook') - - self.assertEqual(msg.subject, "TEST-5: PostTest") - self.assertEqual(msg.content, """Leo Franchi [Administrator] **transitioned** [TEST-5](https://lfranchi-test.atlassian.net/browse/TEST-5) from Resolved to Reopened""") - - def test_workflow_postfunction_started(self): - msg = self.send_jira_message('postfunction_started') - - self.assertEqual(msg.subject, "TEST-7: Gluttony of Post Functions") - self.assertEqual(msg.content, """Leo Franchi [Administrator] **transitioned** [TEST-7](https://lfranchi-test.atlassian.net/browse/TEST-7) from Open to Underway""") - - def test_workflow_postfunction_resolved(self): - msg = self.send_jira_message('postfunction_resolved') - - self.assertEqual(msg.subject, "TEST-7: Gluttony of Post Functions") - self.assertEqual(msg.content, """Leo Franchi [Administrator] **transitioned** [TEST-7](https://lfranchi-test.atlassian.net/browse/TEST-7) from Open to Resolved""") - - def test_mention(self): - msg = self.send_jira_message('watch_mention_updated') - self.assertEqual(msg.subject, "TEST-5: Lunch Decision Needed") - self.assertEqual(msg.content, """Leonardo Franchi [Administrator] **updated** [TEST-5](https://zulipp.atlassian.net/browse/TEST-5) (assigned to @**Othello, the Moor of Venice**): - - -Making a comment, @**Othello, the Moor of Venice** is watching this issue -""") - -class BeanstalkHookTests(AuthedTestCase): - def send_beanstalk_message(self, action): - email = "hamlet@zulip.com" - data = {'payload': self.fixture_data('beanstalk', action)} - return self.send_json_payload(email, "/api/v1/external/beanstalk", - data, - stream_name="commits", - **self.api_auth(email)) - - def test_git_single(self): - msg = self.send_beanstalk_message('git_singlecommit') - self.assertEqual(msg.subject, "work-test") - self.assertEqual(msg.content, """Leo Franchi [pushed](http://lfranchi-svn.beanstalkapp.com/work-test) to branch master - -* [e50508d](http://lfranchi-svn.beanstalkapp.com/work-test/changesets/e50508df): add some stuff -""") - - @slow(0.20, "lots of queries") - def test_git_multiple(self): - msg = self.send_beanstalk_message('git_multiple') - self.assertEqual(msg.subject, "work-test") - self.assertEqual(msg.content, """Leo Franchi [pushed](http://lfranchi-svn.beanstalkapp.com/work-test) to branch master - -* [edf529c](http://lfranchi-svn.beanstalkapp.com/work-test/changesets/edf529c7): Added new file -* [c2a191b](http://lfranchi-svn.beanstalkapp.com/work-test/changesets/c2a191b9): Filled in new file with some stuff -* [2009815](http://lfranchi-svn.beanstalkapp.com/work-test/changesets/20098158): More work to fix some bugs -""") - - def test_svn_addremove(self): - msg = self.send_beanstalk_message('svn_addremove') - self.assertEqual(msg.subject, "svn r3") - self.assertEqual(msg.content, """Leo Franchi pushed [revision 3](http://lfranchi-svn.beanstalkapp.com/work-test/changesets/3): - -> Removed a file and added another one!""") - - def test_svn_changefile(self): - msg = self.send_beanstalk_message('svn_changefile') - self.assertEqual(msg.subject, "svn r2") - self.assertEqual(msg.content, """Leo Franchi pushed [revision 2](http://lfranchi-svn.beanstalkapp.com/work-test/changesets/2): - -> Added some code""") - -class GithubV1HookTests(AuthedTestCase): - - push_content = """zbenjamin [pushed](https://github.com/zbenjamin/zulip-test/compare/4f9adc4777d5...b95449196980) to branch master - -* [48c329a](https://github.com/zbenjamin/zulip-test/commit/48c329a0b68a9a379ff195ee3f1c1f4ab0b2a89e): Add baz -* [06ebe5f](https://github.com/zbenjamin/zulip-test/commit/06ebe5f472a32f6f31fd2a665f0c7442b69cce72): Baz needs to be longer -* [b954491](https://github.com/zbenjamin/zulip-test/commit/b95449196980507f08209bdfdc4f1d611689b7a8): Final edit to baz, I swear -""" - - def test_spam_branch_is_ignored(self): - email = "hamlet@zulip.com" - api_key = self.get_api_key(email) - stream = 'commits' - data = ujson.loads(self.fixture_data('github', 'v1_push')) - data.update({'email': email, - 'api-key': api_key, - 'branches': 'dev,staging', - 'stream': stream, - 'payload': ujson.dumps(data['payload'])}) - url = '/api/v1/external/github' - - # We subscribe to the stream in this test, even though - # it won't get written, to avoid failing for the wrong - # reason. - self.subscribe_to_stream(email, stream) - - prior_count = Message.objects.count() - - result = self.client.post(url, data) - self.assert_json_success(result) - - after_count = Message.objects.count() - self.assertEqual(prior_count, after_count) - - - def basic_test(self, fixture_name, stream_name, expected_subject, expected_content, send_stream=False, branches=None): - email = "hamlet@zulip.com" - api_key = self.get_api_key(email) - data = ujson.loads(self.fixture_data('github', 'v1_' + fixture_name)) - data.update({'email': email, - 'api-key': api_key, - 'payload': ujson.dumps(data['payload'])}) - if send_stream: - data['stream'] = stream_name - if branches is not None: - data['branches'] = branches - msg = self.send_json_payload(email, "/api/v1/external/github", - data, - stream_name=stream_name) - self.assertEqual(msg.subject, expected_subject) - self.assertEqual(msg.content, expected_content) - - def test_user_specified_branches(self): - self.basic_test('push', 'my_commits', 'zulip-test', self.push_content, - send_stream=True, branches="master,staging") - - def test_user_specified_stream(self): - # Around May 2013 the github webhook started to specify the stream. - # Before then, the stream was hard coded to "commits". - self.basic_test('push', 'my_commits', 'zulip-test', self.push_content, - send_stream=True) - - def test_legacy_hook(self): - self.basic_test('push', 'commits', 'zulip-test', self.push_content) - - def test_issues_opened(self): - self.basic_test('issues_opened', 'issues', - "zulip-test: issue 5: The frobnicator doesn't work", - "zbenjamin opened [issue 5](https://github.com/zbenjamin/zulip-test/issues/5)\n\n~~~ quote\nI tried changing the widgets, but I got:\r\n\r\nPermission denied: widgets are immutable\n~~~") - - def test_issue_comment(self): - self.basic_test('issue_comment', 'issues', - "zulip-test: issue 5: The frobnicator doesn't work", - "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/issues/5#issuecomment-23374280) on [issue 5](https://github.com/zbenjamin/zulip-test/issues/5)\n\n~~~ quote\nWhoops, I did something wrong.\r\n\r\nI'm sorry.\n~~~") - - def test_issues_closed(self): - self.basic_test('issues_closed', 'issues', - "zulip-test: issue 5: The frobnicator doesn't work", - "zbenjamin closed [issue 5](https://github.com/zbenjamin/zulip-test/issues/5)") - - def test_pull_request_opened(self): - self.basic_test('pull_request_opened', 'commits', - "zulip-test: pull request 7: Counting is hard.", - "lfaraone opened [pull request 7](https://github.com/zbenjamin/zulip-test/pull/7)\n\n~~~ quote\nOmitted something I think?\n~~~") - - def test_pull_request_closed(self): - self.basic_test('pull_request_closed', 'commits', - "zulip-test: pull request 7: Counting is hard.", - "zbenjamin closed [pull request 7](https://github.com/zbenjamin/zulip-test/pull/7)") - - def test_pull_request_synchronize(self): - self.basic_test('pull_request_synchronize', 'commits', - "zulip-test: pull request 13: Even more cowbell.", - "zbenjamin synchronized [pull request 13](https://github.com/zbenjamin/zulip-test/pull/13)") - - def test_pull_request_comment(self): - self.basic_test('pull_request_comment', 'commits', - "zulip-test: pull request 9: Less cowbell.", - "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/pull/9#issuecomment-24771110) on [pull request 9](https://github.com/zbenjamin/zulip-test/pull/9)\n\n~~~ quote\nYeah, who really needs more cowbell than we already have?\n~~~") - - def test_pull_request_comment_user_specified_stream(self): - self.basic_test('pull_request_comment', 'my_commits', - "zulip-test: pull request 9: Less cowbell.", - "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/pull/9#issuecomment-24771110) on [pull request 9](https://github.com/zbenjamin/zulip-test/pull/9)\n\n~~~ quote\nYeah, who really needs more cowbell than we already have?\n~~~", - send_stream=True) - - def test_commit_comment(self): - self.basic_test('commit_comment', 'commits', - "zulip-test: commit 7c994678d2f98797d299abed852d3ff9d0834533", - "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/commit/7c994678d2f98797d299abed852d3ff9d0834533#commitcomment-4252302)\n\n~~~ quote\nAre we sure this is enough cowbell?\n~~~") - - def test_commit_comment_line(self): - self.basic_test('commit_comment_line', 'commits', - "zulip-test: commit 7c994678d2f98797d299abed852d3ff9d0834533", - "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/commit/7c994678d2f98797d299abed852d3ff9d0834533#commitcomment-4252307) on `cowbell`, line 13\n\n~~~ quote\nThis line adds /unlucky/ cowbell (because of its line number). We should remove it.\n~~~") - -class GithubV2HookTests(AuthedTestCase): - - push_content = """zbenjamin [pushed](https://github.com/zbenjamin/zulip-test/compare/4f9adc4777d5...b95449196980) to branch master - -* [48c329a](https://github.com/zbenjamin/zulip-test/commit/48c329a0b68a9a379ff195ee3f1c1f4ab0b2a89e): Add baz -* [06ebe5f](https://github.com/zbenjamin/zulip-test/commit/06ebe5f472a32f6f31fd2a665f0c7442b69cce72): Baz needs to be longer -* [b954491](https://github.com/zbenjamin/zulip-test/commit/b95449196980507f08209bdfdc4f1d611689b7a8): Final edit to baz, I swear -""" - - def test_spam_branch_is_ignored(self): - email = "hamlet@zulip.com" - api_key = self.get_api_key(email) - stream = 'commits' - data = ujson.loads(self.fixture_data('github', 'v2_push')) - data.update({'email': email, - 'api-key': api_key, - 'branches': 'dev,staging', - 'stream': stream, - 'payload': ujson.dumps(data['payload'])}) - url = '/api/v1/external/github' - - # We subscribe to the stream in this test, even though - # it won't get written, to avoid failing for the wrong - # reason. - self.subscribe_to_stream(email, stream) - - prior_count = Message.objects.count() - - result = self.client.post(url, data) - self.assert_json_success(result) - - after_count = Message.objects.count() - self.assertEqual(prior_count, after_count) - - - def basic_test(self, fixture_name, stream_name, expected_subject, expected_content, send_stream=False, branches=None): - email = "hamlet@zulip.com" - api_key = self.get_api_key(email) - data = ujson.loads(self.fixture_data('github', 'v2_' + fixture_name)) - data.update({'email': email, - 'api-key': api_key, - 'payload': ujson.dumps(data['payload'])}) - if send_stream: - data['stream'] = stream_name - if branches is not None: - data['branches'] = branches - msg = self.send_json_payload(email, "/api/v1/external/github", - data, - stream_name=stream_name) - self.assertEqual(msg.subject, expected_subject) - self.assertEqual(msg.content, expected_content) - - def test_user_specified_branches(self): - self.basic_test('push', 'my_commits', 'zulip-test', self.push_content, - send_stream=True, branches="master,staging") - - def test_user_specified_stream(self): - # Around May 2013 the github webhook started to specify the stream. - # Before then, the stream was hard coded to "commits". - self.basic_test('push', 'my_commits', 'zulip-test', self.push_content, - send_stream=True) - - def test_legacy_hook(self): - self.basic_test('push', 'commits', 'zulip-test', self.push_content) - - def test_issues_opened(self): - self.basic_test('issues_opened', 'issues', - "zulip-test: issue 5: The frobnicator doesn't work", - "zbenjamin opened [issue 5](https://github.com/zbenjamin/zulip-test/issues/5)\n\n~~~ quote\nI tried changing the widgets, but I got:\r\n\r\nPermission denied: widgets are immutable\n~~~") - - def test_issue_comment(self): - self.basic_test('issue_comment', 'issues', - "zulip-test: issue 5: The frobnicator doesn't work", - "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/issues/5#issuecomment-23374280) on [issue 5](https://github.com/zbenjamin/zulip-test/issues/5)\n\n~~~ quote\nWhoops, I did something wrong.\r\n\r\nI'm sorry.\n~~~") - - def test_issues_closed(self): - self.basic_test('issues_closed', 'issues', - "zulip-test: issue 5: The frobnicator doesn't work", - "zbenjamin closed [issue 5](https://github.com/zbenjamin/zulip-test/issues/5)") - - def test_pull_request_opened(self): - self.basic_test('pull_request_opened', 'commits', - "zulip-test: pull request 7: Counting is hard.", - "lfaraone opened [pull request 7](https://github.com/zbenjamin/zulip-test/pull/7)\n\n~~~ quote\nOmitted something I think?\n~~~") - - def test_pull_request_closed(self): - self.basic_test('pull_request_closed', 'commits', - "zulip-test: pull request 7: Counting is hard.", - "zbenjamin closed [pull request 7](https://github.com/zbenjamin/zulip-test/pull/7)") - - def test_pull_request_synchronize(self): - self.basic_test('pull_request_synchronize', 'commits', - "zulip-test: pull request 13: Even more cowbell.", - "zbenjamin synchronized [pull request 13](https://github.com/zbenjamin/zulip-test/pull/13)") - - def test_pull_request_comment(self): - self.basic_test('pull_request_comment', 'commits', - "zulip-test: pull request 9: Less cowbell.", - "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/pull/9#issuecomment-24771110) on [pull request 9](https://github.com/zbenjamin/zulip-test/pull/9)\n\n~~~ quote\nYeah, who really needs more cowbell than we already have?\n~~~") - - def test_pull_request_comment_user_specified_stream(self): - self.basic_test('pull_request_comment', 'my_commits', - "zulip-test: pull request 9: Less cowbell.", - "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/pull/9#issuecomment-24771110) on [pull request 9](https://github.com/zbenjamin/zulip-test/pull/9)\n\n~~~ quote\nYeah, who really needs more cowbell than we already have?\n~~~", - send_stream=True) - - def test_commit_comment(self): - self.basic_test('commit_comment', 'commits', - "zulip-test: commit 7c994678d2f98797d299abed852d3ff9d0834533", - "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/commit/7c994678d2f98797d299abed852d3ff9d0834533#commitcomment-4252302)\n\n~~~ quote\nAre we sure this is enough cowbell?\n~~~") - - def test_commit_comment_line(self): - self.basic_test('commit_comment_line', 'commits', - "zulip-test: commit 7c994678d2f98797d299abed852d3ff9d0834533", - "zbenjamin [commented](https://github.com/zbenjamin/zulip-test/commit/7c994678d2f98797d299abed852d3ff9d0834533#commitcomment-4252307) on `cowbell`, line 13\n\n~~~ quote\nThis line adds /unlucky/ cowbell (because of its line number). We should remove it.\n~~~") - -class PivotalV3HookTests(AuthedTestCase): - - def send_pivotal_message(self, name): - email = "hamlet@zulip.com" - api_key = self.get_api_key(email) - return self.send_json_payload(email, "/api/v1/external/pivotal?api_key=%s&stream=%s" % (api_key,"pivotal"), - self.fixture_data('pivotal', name, file_type='xml'), - stream_name="pivotal", - content_type="application/xml") - - def test_accepted(self): - msg = self.send_pivotal_message('accepted') - self.assertEqual(msg.subject, 'My new Feature story') - self.assertEqual(msg.content, 'Leo Franchi accepted "My new Feature story" \ -[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48276573)') - - def test_commented(self): - msg = self.send_pivotal_message('commented') - self.assertEqual(msg.subject, 'Comment added') - self.assertEqual(msg.content, 'Leo Franchi added comment: "FIX THIS NOW" \ -[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48276573)') - - def test_created(self): - msg = self.send_pivotal_message('created') - self.assertEqual(msg.subject, 'My new Feature story') - self.assertEqual(msg.content, 'Leo Franchi added "My new Feature story" \ -(unscheduled feature):\n\n~~~ quote\nThis is my long description\n~~~\n\n \ -[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48276573)') - - def test_delivered(self): - msg = self.send_pivotal_message('delivered') - self.assertEqual(msg.subject, 'Another new story') - self.assertEqual(msg.content, 'Leo Franchi delivered "Another new story" \ -[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48278289)') - - def test_finished(self): - msg = self.send_pivotal_message('finished') - self.assertEqual(msg.subject, 'Another new story') - self.assertEqual(msg.content, 'Leo Franchi finished "Another new story" \ -[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48278289)') - - def test_moved(self): - msg = self.send_pivotal_message('moved') - self.assertEqual(msg.subject, 'My new Feature story') - self.assertEqual(msg.content, 'Leo Franchi edited "My new Feature story" \ -[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48276573)') - - def test_rejected(self): - msg = self.send_pivotal_message('rejected') - self.assertEqual(msg.subject, 'Another new story') - self.assertEqual(msg.content, 'Leo Franchi rejected "Another new story" with comments: \ -"Not good enough, sorry" [(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48278289)') - - def test_started(self): - msg = self.send_pivotal_message('started') - self.assertEqual(msg.subject, 'Another new story') - self.assertEqual(msg.content, 'Leo Franchi started "Another new story" \ -[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48278289)') - - def test_created_estimate(self): - msg = self.send_pivotal_message('created_estimate') - self.assertEqual(msg.subject, 'Another new story') - self.assertEqual(msg.content, 'Leo Franchi added "Another new story" \ -(unscheduled feature worth 2 story points):\n\n~~~ quote\nSome loong description\n~~~\n\n \ -[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48278289)') - - def test_type_changed(self): - msg = self.send_pivotal_message('type_changed') - self.assertEqual(msg.subject, 'My new Feature story') - self.assertEqual(msg.content, 'Leo Franchi edited "My new Feature story" \ -[(view)](https://www.pivotaltracker.com/s/projects/807213/stories/48276573)') - -class PivotalV5HookTests(AuthedTestCase): - def send_pivotal_message(self, name): - email = "hamlet@zulip.com" - api_key = self.get_api_key(email) - return self.send_json_payload(email, "/api/v1/external/pivotal?api_key=%s&stream=%s" % (api_key,"pivotal"), - self.fixture_data('pivotal', "v5_" + name, file_type='json'), - stream_name="pivotal", - content_type="application/xml") - - def test_accepted(self): - msg = self.send_pivotal_message('accepted') - self.assertEqual(msg.subject, '#63486316: Story of the Year') - self.assertEqual(msg.content, """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Story of the Year](http://www.pivotaltracker.com/story/show/63486316): -* state changed from **unstarted** to **accepted** -""") - - def test_commented(self): - msg = self.send_pivotal_message('commented') - self.assertEqual(msg.subject, '#63486316: Story of the Year') - self.assertEqual(msg.content, """Leo Franchi added a comment to [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Story of the Year](http://www.pivotaltracker.com/story/show/63486316): -~~~quote -A comment on the story -~~~""") - - def test_created(self): - msg = self.send_pivotal_message('created') - self.assertEqual(msg.subject, '#63495662: Story that I created') - self.assertEqual(msg.content, """Leo Franchi created bug: [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Story that I created](http://www.pivotaltracker.com/story/show/63495662) -* State is **unscheduled** -* Description is - -> What a description""") - - def test_delivered(self): - msg = self.send_pivotal_message('delivered') - self.assertEqual(msg.subject, '#63486316: Story of the Year') - self.assertEqual(msg.content, """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Story of the Year](http://www.pivotaltracker.com/story/show/63486316): -* state changed from **accepted** to **delivered** -""") - - def test_finished(self): - msg = self.send_pivotal_message('finished') - self.assertEqual(msg.subject, '#63486316: Story of the Year') - self.assertEqual(msg.content, """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Story of the Year](http://www.pivotaltracker.com/story/show/63486316): -* state changed from **delivered** to **accepted** -""") - - def test_moved(self): - msg = self.send_pivotal_message('moved') - self.assertEqual(msg.subject, '#63496066: Pivotal Test') - self.assertEqual(msg.content, """Leo Franchi moved [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Pivotal Test](http://www.pivotaltracker.com/story/show/63496066) from **unstarted** to **unscheduled**""") - - def test_rejected(self): - msg = self.send_pivotal_message('rejected') - self.assertEqual(msg.subject, '#63486316: Story of the Year') - self.assertEqual(msg.content, """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Story of the Year](http://www.pivotaltracker.com/story/show/63486316): -* Comment added: -~~~quote -Try again next time -~~~ -* state changed from **delivered** to **rejected** -""") - - def test_started(self): - msg = self.send_pivotal_message('started') - self.assertEqual(msg.subject, '#63495972: Fresh Story') - self.assertEqual(msg.content, """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Fresh Story](http://www.pivotaltracker.com/story/show/63495972): -* state changed from **unstarted** to **started** -""") - - def test_created_estimate(self): - msg = self.send_pivotal_message('created_estimate') - self.assertEqual(msg.subject, '#63496066: Pivotal Test') - self.assertEqual(msg.content, """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Pivotal Test](http://www.pivotaltracker.com/story/show/63496066): -* estimate is now **3 points** -""") - - def test_type_changed(self): - msg = self.send_pivotal_message('type_changed') - self.assertEqual(msg.subject, '#63496066: Pivotal Test') - self.assertEqual(msg.content, """Leo Franchi updated [Hard Code](https://www.pivotaltracker.com/s/projects/807213): [Pivotal Test](http://www.pivotaltracker.com/story/show/63496066): -* estimate changed from 3 to **0 points** -* type changed from **feature** to **bug** -""") - -class NewRelicHookTests(AuthedTestCase): - def send_new_relic_message(self, name): - email = "hamlet@zulip.com" - api_key = self.get_api_key(email) - return self.send_json_payload(email, "/api/v1/external/newrelic?api_key=%s&stream=%s" % (api_key,"newrelic"), - self.fixture_data('newrelic', name, file_type='txt'), - stream_name="newrelic", - content_type="application/x-www-form-urlencoded") - - def test_alert(self): - msg = self.send_new_relic_message('alert') - self.assertEqual(msg.subject, "Apdex score fell below critical level of 0.90") - self.assertEqual(msg.content, 'Alert opened on [application name]: \ -Apdex score fell below critical level of 0.90\n\ -[View alert](https://rpm.newrelc.com/accounts/[account_id]/applications/[application_id]/incidents/[incident_id])') - - def test_deployment(self): - msg = self.send_new_relic_message('deployment') - self.assertEqual(msg.subject, 'Test App deploy') - self.assertEqual(msg.content, '`1242` deployed by **Zulip Test**\n\ -Description sent via curl\n\nChangelog string') - -class StashHookTests(AuthedTestCase): - def test_stash_message(self): - """ - Messages are generated by Stash on a `git push`. - - The subject describes the repo and Stash "project". The - content describes the commits pushed. - """ - email = "hamlet@zulip.com" - msg = self.send_json_payload( - email, "/api/v1/external/stash?stream=commits", - self.fixture_data("stash", "push", file_type="json"), - stream_name="commits", - content_type="application/x-www-form-urlencoded", - **self.api_auth(email)) - - self.assertEqual(msg.subject, u"Secret project/Operation unicorn: master") - self.assertEqual(msg.content, """`f259e90` was pushed to **master** in **Secret project/Operation unicorn** with: - -* `f259e90`: Updating poms ...""") - -class FreshdeskHookTests(AuthedTestCase): - def generate_webhook_response(self, fixture): - """ - Helper function to handle the webhook boilerplate. - """ - email = "hamlet@zulip.com" - return self.send_json_payload( - email, "/api/v1/external/freshdesk?stream=freshdesk", - self.fixture_data("freshdesk", fixture, file_type="json"), - stream_name="freshdesk", - content_type="application/x-www-form-urlencoded", - **self.api_auth(email)) - - def test_ticket_creation(self): - """ - Messages are generated on ticket creation through Freshdesk's - "Dispatch'r" service. - """ - msg = self.generate_webhook_response("ticket_created") - self.assertEqual(msg.subject, u"#11: Test ticket subject ☃") - self.assertEqual(msg.content, u"""Requester ☃ Bob created [ticket #11](http://test1234zzz.freshdesk.com/helpdesk/tickets/11): - -~~~ quote -Test ticket description ☃. -~~~ - -Type: **Incident** -Priority: **High** -Status: **Pending**""") - - def test_status_change(self): - """ - Messages are generated when a ticket's status changes through - Freshdesk's "Observer" service. - """ - msg = self.generate_webhook_response("status_changed") - self.assertEqual(msg.subject, u"#11: Test ticket subject ☃") - self.assertEqual(msg.content, """Requester Bob updated [ticket #11](http://test1234zzz.freshdesk.com/helpdesk/tickets/11): - -Status: **Resolved** => **Waiting on Customer**""") - - def test_priority_change(self): - """ - Messages are generated when a ticket's priority changes through - Freshdesk's "Observer" service. - """ - msg = self.generate_webhook_response("priority_changed") - self.assertEqual(msg.subject, u"#11: Test ticket subject") - self.assertEqual(msg.content, """Requester Bob updated [ticket #11](http://test1234zzz.freshdesk.com/helpdesk/tickets/11): - -Priority: **High** => **Low**""") - - def note_change(self, fixture, note_type): - """ - Messages are generated when a note gets added to a ticket through - Freshdesk's "Observer" service. - """ - msg = self.generate_webhook_response(fixture) - self.assertEqual(msg.subject, u"#11: Test ticket subject") - self.assertEqual(msg.content, """Requester Bob added a %s note to [ticket #11](http://test1234zzz.freshdesk.com/helpdesk/tickets/11).""" % (note_type,)) - - def test_private_note_change(self): - self.note_change("private_note", "private") - - def test_public_note_change(self): - self.note_change("public_note", "public") - - def test_inline_image(self): - """ - Freshdesk sends us descriptions as HTML, so we have to make the - descriptions Zulip markdown-friendly while still doing our best to - preserve links and images. - """ - msg = self.generate_webhook_response("inline_images") - self.assertEqual(msg.subject, u"#12: Not enough ☃ guinea pigs") - self.assertIn("[guinea_pig.png](http://cdn.freshdesk.com/data/helpdesk/attachments/production/12744808/original/guinea_pig.png)", msg.content) - -class ZenDeskHookTests(AuthedTestCase): - - def generate_webhook_response(self, ticket_title='User can\'t login', - ticket_id=54, message='Message', - stream_name='zendesk'): - data = { - 'ticket_title': ticket_title, - 'ticket_id': ticket_id, - 'message': message, - 'stream': stream_name, - } - email = 'hamlet@zulip.com' - self.subscribe_to_stream(email, stream_name) - result = self.client.post('/api/v1/external/zendesk', data, - **self.api_auth(email)) - self.assert_json_success(result) - - # Check the correct message was sent - msg = Message.objects.filter().order_by('-id')[0] - self.assertEqual(msg.sender.email, email) - - return msg - - def test_subject(self): - msg = self.generate_webhook_response(ticket_id=4, ticket_title="Test ticket") - self.assertEqual(msg.subject, '#4: Test ticket') - - def test_long_subject(self): - msg = self.generate_webhook_response(ticket_id=4, ticket_title="Test ticket" + '!' * 80) - self.assertEqual(msg.subject, '#4: Test ticket' + '!' * 42 + '...') - - def test_content(self): - msg = self.generate_webhook_response(message='New comment:\n> It is better\n* here') - self.assertEqual(msg.content, 'New comment:\n> It is better\n* here') - class RateLimitTests(AuthedTestCase): def setUp(self):