From 4c582a4ddd6a14533795d4cd15039288048f170b Mon Sep 17 00:00:00 2001
From: sidpremkumar <sid.premkumar@gmail.com>
Date: Aug 13 2019 13:18:02 +0000
Subject: [PATCH 1/2] Adding min coverage to tox


---

diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000..d8a8a30
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,10 @@
+[run]
+branch=True
+source=sync2jira/
+omit=sync2jira/mailer.py
+
+[report]
+fail_under=60
+
+[html]
+directory=./coverage_report
\ No newline at end of file
diff --git a/tox.ini b/tox.ini
index 7dbb338..5f6c94f 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = py37,flake8
+envlist = clean, py37,flake8
 
 [testenv]
 setenv =
@@ -10,11 +10,12 @@ basepython =
 deps =
     -r{toxinidir}/requirements.txt
     -r{toxinidir}/test-requirements.txt
-    pytest
     nose
+    pytest
+    pytest-cov
 sitepackages = False
 commands =
-    pytest {posargs} --junitxml=xunit-tests.xml
+    pytest {posargs} --cov --cov-append --cov-report html:htmlcov-py36 --junitxml=xunit-tests.xml
 
 [testenv:flake8]
 basepython = python3
@@ -27,3 +28,9 @@ max-line-length=140
 
 [pep8]
 max-line-length=140
+
+[testenv:clean]
+basepython = python3
+deps = coverage
+skip_install = False
+commands = coverage erase
\ No newline at end of file

From 6aad8c2fe18fec5ce5254be39d3ba8eb652c61d5 Mon Sep 17 00:00:00 2001
From: sidpremkumar <sid.premkumar@gmail.com>
Date: Aug 13 2019 13:55:11 +0000
Subject: [PATCH 2/2] Add 75% min coverage and added tests accordingly


---

diff --git a/.coveragerc b/.coveragerc
index d8a8a30..fdbd371 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -4,7 +4,7 @@ source=sync2jira/
 omit=sync2jira/mailer.py
 
 [report]
-fail_under=60
+fail_under=75
 
 [html]
 directory=./coverage_report
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 53c38b5..08d37fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,3 +13,4 @@ venv/*
 venv3/*
 xunit-tests.xml
 docs/build/*
+htmlcov-py36/*
diff --git a/tests/test_downstream.py b/tests/test_downstream.py
index 70c742f..b6dee26 100644
--- a/tests/test_downstream.py
+++ b/tests/test_downstream.py
@@ -5,7 +5,7 @@ try:
     from unittest.mock import MagicMock  # noqa: F401
 except ImportError:
     from mock import MagicMock  # noqa: F401
-import os
+from datetime import  datetime
 
 import sync2jira.downstream as d
 from sync2jira.intermediary import Issue
@@ -1197,6 +1197,59 @@ class TestDownstream(unittest.TestCase):
             user={'name': 'mock_name', 'email': 'mock_email'})
         mock_mailer().send.asset_called_with('test')
 
+    @mock.patch(PATH + 'jinja2')
+    @mock.patch(PATH + 'send_mail')
+    @mock.patch('jira.client.JIRA')
+    def test_alert_user_multiple_users(self,
+                                       mock_client,
+                                       mock_mailer,
+                                       mock_jinja, ):
+        """
+        This tests 'alert_user_of_duplicate_issues' function
+        where searching returns multiple users
+        """
+        # Set up return values
+        mock_downstream_issue = MagicMock()
+        mock_downstream_issue.key = 'mock_key'
+        bad_downstream_issue = MagicMock()
+        bad_downstream_issue.key = 'mock_key'
+        bad_downstream_issue.fields.status.name = 'To Do'
+        mock_results_of_query = [mock_downstream_issue, bad_downstream_issue]
+        mock_search_user_result1 = MagicMock()
+        mock_search_user_result1.displayName = 'bad_name'
+        mock_search_user_result1.emailAddress = 'bad_email'
+        mock_search_user_result1.key = 'bad_owner'
+        mock_search_user_result2 = MagicMock()
+        mock_search_user_result2.displayName = 'mock_name'
+        mock_search_user_result2.emailAddress = 'mock_email'
+        mock_search_user_result2.key = 'mock_owner'
+        mock_client.search_users.return_value = [mock_search_user_result1, mock_search_user_result2]
+        mock_template = MagicMock(name='template')
+        mock_template.render.return_value = 'mock_html_text'
+        mock_template_env = MagicMock(name='templateEnv')
+        mock_template_env.get_template.return_value = mock_template
+        mock_jinja.Environment.return_value = mock_template_env
+
+        # Call the function
+        d.alert_user_of_duplicate_issues(
+            issue=self.mock_issue,
+            final_result=[mock_downstream_issue],
+            results_of_query=mock_results_of_query,
+            config=self.mock_config,
+            client=mock_client
+        )
+
+        # Assert everything was called correctly
+        mock_client.search_users.assert_any_call('mock_owner')
+        mock_client.search_users.assert_any_call('mock_admin')
+        mock_template.render.assert_called_with(
+            admins=[{'name': 'mock_name', 'email': 'mock_email'}],
+            duplicate_issues=[{'url': 'mock_server/browse/mock_key', 'title': 'mock_key'}],
+            issue=self.mock_issue,
+            selected_issue={'url': 'mock_server/browse/mock_key', 'title': 'mock_key'},
+            user={'name': 'mock_name', 'email': 'mock_email'})
+        mock_mailer().send.asset_called_with('test')
+
     def test_find_username(self):
         """
         Tests 'find_username' function
@@ -1210,7 +1263,6 @@ class TestDownstream(unittest.TestCase):
         # Assert everything was called correctly
         self.assertEqual(response, 'mock_user')
 
-
     @mock.patch('jira.client.JIRA')
     def test_check_comments_for_duplicates(self,
                                            mock_client):
@@ -1235,3 +1287,105 @@ class TestDownstream(unittest.TestCase):
         self.assertEqual(response, 'Successful Call!')
         mock_client.comments.assert_called_with(self.mock_downstream)
         mock_client.issue.assert_called_with('TEST-1234')
+
+    @mock.patch(PATH + '_comment_format')
+    @mock.patch(PATH + '_comment_format_legacy')
+    def test_find_comment_in_jira_legacy(self,
+                                         mock_comment_format_legacy,
+                                         mock_comment_format):
+        """
+        This function tests '_find_comment_in_jira' where we find a legacy comment
+        """
+        # Set up return values
+        mock_comment_format.return_value = 'mock_comment_body'
+        mock_comment_format_legacy.return_value = 'mock_legacy_comment_body'
+        mock_jira_comment = MagicMock()
+        mock_jira_comment.raw = {'body': 'mock_legacy_comment_body'}
+        mock_comment = {
+            'id': '12345',
+            'date_created': datetime(2019, 8, 8)
+        }
+
+        # Call the function
+        response = d._find_comment_in_jira(mock_comment, [mock_jira_comment])
+
+        # Assert everything was called correctly
+        mock_comment_format_legacy.assert_called_with(mock_comment)
+        mock_comment_format.assert_called_with(mock_comment)
+        self.assertEqual(response, mock_jira_comment)
+
+    @mock.patch(PATH + '_comment_format')
+    @mock.patch(PATH + '_comment_format_legacy')
+    def test_find_comment_in_jira_id(self,
+                                     mock_comment_format_legacy,
+                                     mock_comment_format):
+        """
+        This function tests '_find_comment_in_jira' where we match an ID
+        """
+        # Set up return values
+        mock_comment_format.return_value = 'mock_comment_body'
+        mock_comment_format_legacy.return_value = 'mock_legacy_comment_body'
+        mock_jira_comment = MagicMock()
+        mock_jira_comment.raw = {'body': '12345'}
+        mock_comment = {
+            'id': '12345',
+            'date_created': datetime(2019, 8, 8)
+        }
+
+        # Call the function
+        response = d._find_comment_in_jira(mock_comment, [mock_jira_comment])
+
+        # Assert everything was called correctly
+        mock_comment_format_legacy.assert_called_with(mock_comment)
+        mock_comment_format.assert_called_with(mock_comment)
+        self.assertEqual(response, mock_jira_comment)
+
+    @mock.patch(PATH + '_comment_format')
+    @mock.patch(PATH + '_comment_format_legacy')
+    def test_find_comment_in_jira_old_comment(self,
+                                              mock_comment_format_legacy,
+                                              mock_comment_format):
+        """
+        This function tests '_find_comment_in_jira' where we find a old comment
+        """
+        # Set up return values
+        mock_comment_format.return_value = 'mock_comment_body'
+        mock_comment_format_legacy.return_value = 'mock_legacy_comment_body'
+        mock_jira_comment = MagicMock()
+        mock_jira_comment.raw = {'body': 'old_comment'}
+        mock_comment = {
+            'id': '12345',
+            'date_created': datetime(2019, 1, 1)
+        }
+
+        # Call the function
+        response = d._find_comment_in_jira(mock_comment, [mock_jira_comment])
+
+        # Assert everything was called correctly
+        mock_comment_format_legacy.assert_called_with(mock_comment)
+        mock_comment_format.assert_called_with(mock_comment)
+        self.assertEqual(response, mock_jira_comment)
+
+    @mock.patch(PATH + '_comment_format')
+    @mock.patch(PATH + '_comment_format_legacy')
+    def test_find_comment_in_jira_none(self,
+                                       mock_comment_format_legacy,
+                                       mock_comment_format):
+        """
+        This function tests '_find_comment_in_jira' where we return None
+        """
+        # Set up return values
+        mock_comment_format.return_value = 'mock_comment_body'
+        mock_comment_format_legacy.return_value = 'mock_legacy_comment_body'
+        mock_comment = {
+            'id': '12345',
+            'date_created': datetime(2019, 1, 1)
+        }
+
+        # Call the function
+        response = d._find_comment_in_jira(mock_comment, [])
+
+        # Assert everything was called correctly
+        mock_comment_format_legacy.assert_called_with(mock_comment)
+        mock_comment_format.assert_called_with(mock_comment)
+        self.assertEqual(response, None)
\ No newline at end of file
diff --git a/tests/test_intermediary.py b/tests/test_intermediary.py
index dd39dc2..420769e 100644
--- a/tests/test_intermediary.py
+++ b/tests/test_intermediary.py
@@ -79,9 +79,9 @@ class TestIntermediary(unittest.TestCase):
         self.assertEqual(response.id, 'mock_date')
         self.assertEqual(response.downstream, 'mock_downstream')
 
-    def test_from_github(self):
+    def test_from_github_open(self):
         """
-        This tests the 'from_github' function under the Issue class
+        This tests the 'from_github' function under the Issue class where the state is open
         """
         # Set up return values
         mock_issue = {
@@ -128,3 +128,53 @@ class TestIntermediary(unittest.TestCase):
         self.assertEqual(response.status, 'Open')
         self.assertEqual(response.id, '1234')
         self.assertEqual(response.downstream, 'mock_downstream')
+
+    def test_from_github_closed(self):
+        """
+        This tests the 'from_github' function under the Issue class where the state is closed
+        """
+        # Set up return values
+        mock_issue = {
+            'comments': [{
+                'author': 'mock_author',
+                'name': 'mock_name',
+                'body': 'mock_body',
+                'id': 'mock_id',
+                'date_created': 'mock_date'
+            }],
+            'title': 'mock_title',
+            'html_url': 'mock_url',
+            'id': 1234,
+            'labels': 'mock_tags',
+            'milestone': 'mock_milestone',
+            'priority': 'mock_priority',
+            'body': 'mock_content',
+            'user': 'mock_reporter',
+            'assignees': 'mock_assignee',
+            'state': 'closed',
+            'date_created': 'mock_date'
+        }
+
+        # Call the function
+        response = i.Issue.from_github(
+            upstream='github',
+            issue=mock_issue,
+            config=self.mock_config
+        )
+
+        # Assert that we made the calls correctly
+        self.assertEqual(response.source, 'github')
+        self.assertEqual(response.title, '[github] mock_title')
+        self.assertEqual(response.url, 'mock_url')
+        self.assertEqual(response.upstream, 'github')
+        self.assertEqual(response.comments, [{'body': 'mock_body', 'name': 'mock_name', 'author': 'mock_author',
+                                              'changed': None, 'date_created': 'mock_date', 'id': 'mock_id'}])
+        self.assertEqual(response.tags, 'mock_tags')
+        self.assertEqual(response.fixVersion, ['mock_milestone'])
+        self.assertEqual(response.priority, None)
+        self.assertEqual(response.content, 'mock_content')
+        self.assertEqual(response.reporter, 'mock_reporter')
+        self.assertEqual(response.assignee, 'mock_assignee')
+        self.assertEqual(response.status, 'Closed')
+        self.assertEqual(response.id, '1234')
+        self.assertEqual(response.downstream, 'mock_downstream')
diff --git a/tests/test_main.py b/tests/test_main.py
index 82c6328..d9ab496 100644
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -250,9 +250,9 @@ class TestMain(unittest.TestCase):
     @mock.patch(PATH + 'd')
     @mock.patch(PATH + 'fedmsg')
     def test_listen(self,
-                             mock_fedmsg,
-                             mock_d,
-                             mock_u):
+                    mock_fedmsg,
+                    mock_d,
+                    mock_u):
         """
         Test 'listen' function where everything goes smoothly
         """
@@ -266,4 +266,30 @@ class TestMain(unittest.TestCase):
         # Assert everything was called correctly
         mock_d.sync_with_jira.assert_called_with('dummy_issue', self.mock_config)
         mock_u.handle_github_message.assert_called_with(self.mock_message, self.mock_config)
-        mock_u.handle_pagure_message.assert_not_called()
\ No newline at end of file
+        mock_u.handle_pagure_message.assert_not_called()
+
+    @mock.patch(PATH + 'send_mail')
+    @mock.patch(PATH + 'jinja2')
+    def test_report_failure(self,
+                            mock_jinja2,
+                            mock_send_mail):
+        """
+        Tests 'report_failure' function
+        """
+        # Set up return values
+        mock_templateLoader = MagicMock()
+        mock_templateEnv = MagicMock()
+        mock_template = MagicMock()
+        mock_template.render.return_value = 'mock_html'
+        mock_templateEnv.get_template.return_value = mock_template
+        mock_jinja2.FileSystemLoader.return_value = mock_templateLoader
+        mock_jinja2.Environment.return_value = mock_templateEnv
+
+        # Call the function
+        m.report_failure({'sync2jira': {'admins': [{'mock_user': 'mock_email'}]}})
+
+        # Assert everything was called correctly
+        mock_send_mail.assert_called_with(cc=None,
+                                          recipients=['mock_email'],
+                                          subject='Sync2Jira Has Failed!',
+                                          text='mock_html')
\ No newline at end of file

