def setUp(self):
     self.sonar = SonarAPIHandler(user='******', password='******')
     username = str(uuid.uuid1())
     self.test_user = self.sonar.create_user(
         username,
         'qwerty',
         username,
         "{}@example.com".format(username)
     ).json().get('user')
class TestUsers(TestCase):
    def setUp(self):
        self.sonar = SonarAPIHandler(user='******', password='******')
        self.test_user = str(uuid.uuid1())

    def test_get_users(self):
        users = self.sonar.get_users().json()
        self.assertIn('users', users)

    def test_create_update_deactivate_user(self):
        res = self.sonar.create_user(self.test_user, 'qwerty', name=self.test_user).json()
        self.assertIn('user', res)
        email = "{}@example.com".format(self.test_user)
        res = self.sonar.update_user(self.test_user, email=email).json()
        self.assertEqual(res['user']['email'], email)
        res = self.sonar.deactivate_user(self.test_user).json()
        self.assertFalse(res['user']['active'])
    def test_url_building(self):
        test = SonarAPIHandler(host='http://localhost', port=9001,
                               base_path='/testing')
        self.assertEqual(
            "http://localhost:9001/testing{}".format(test.RESOURCES_ENDPOINT),
            test._get_url(test.RESOURCES_ENDPOINT))

        test = SonarAPIHandler(host='http://localhost', port=9001)
        self.assertEqual(
            "http://localhost:9001{}".format(test.RESOURCES_ENDPOINT),
            test._get_url(test.RESOURCES_ENDPOINT))

        test = SonarAPIHandler(host='http://localhost')
        self.assertEqual(
            "http://localhost:9000{}".format(test.RESOURCES_ENDPOINT),
            test._get_url(test.RESOURCES_ENDPOINT))
    def test_url_building(self):
        test = SonarAPIHandler(host="http://localhost", port=9001, base_path="/testing")
        self.assertEqual(
            "http://localhost:9001/testing{}".format(test.RESOURCES_ENDPOINT), test._get_url(test.RESOURCES_ENDPOINT)
        )

        test = SonarAPIHandler(host="http://localhost", port=9001)
        self.assertEqual(
            "http://localhost:9001{}".format(test.RESOURCES_ENDPOINT), test._get_url(test.RESOURCES_ENDPOINT)
        )

        test = SonarAPIHandler(host="http://localhost")
        self.assertEqual(
            "http://localhost:9000{}".format(test.RESOURCES_ENDPOINT), test._get_url(test.RESOURCES_ENDPOINT)
        )
Example #5
0
 def setUp(self):
     self.h = SonarAPIHandler(user='******', password='******')
Example #6
0
class SonarAPIHandlerTest(TestCase):
    def setUp(self):
        self.h = SonarAPIHandler(user='******', password='******')

    @mock.patch('sonarqube_api.api.requests.Session.get')
    def test_validate_auth(self, mock_res):
        resp = mock.MagicMock(status_code=200)
        mock_res.return_value = resp

        # Error, not authenticated
        resp.json.return_value = {'valid': False}
        self.assertFalse(self.h.validate_authentication())

        # Weird result, always assume invalid
        resp.json.return_value = {'wtf': 'lala'}
        self.assertFalse(self.h.validate_authentication())

        # OK, authenticated
        resp.json.return_value = {'valid': True}
        self.assertTrue(self.h.validate_authentication())

    @mock.patch('sonarqube_api.api.requests.Session.get')
    def test_errors(self, mock_get):
        # Empty response , cannot get next
        resp = mock.MagicMock(status_code=200)
        resp.json.return_value = {'p': 1, 'ps': 20, 'total': 0, 'metrics': []}
        mock_get.return_value = resp
        self.assertRaises(StopIteration, next, self.h.get_metrics())

        # Invalid data, raises ValidationError
        resp.status_code = 400
        resp.json.return_value = {
            'errors': [{
                'msg': 'invalid data for field'
            }]
        }
        self.assertRaises(ValidationError, next, self.h.get_metrics())

        # Not authenticated, raises AuthError
        resp.status_code = 401
        resp.reason = 'Unauthorized'
        self.assertRaises(AuthError, next, self.h.get_metrics())

        # Not authorized, raises AuthError
        resp.status_code = 403
        resp.reason = 'Forbidden'
        self.assertRaises(AuthError, next, self.h.get_metrics())

        # Not found, generic client error
        resp.status_code = 404
        resp.reason = 'Not Found'
        self.assertRaises(ClientError, next, self.h.get_metrics())

        # Server error
        resp.status_code = 500
        resp.reason = 'Internal Server Error'
        self.assertRaises(ServerError, next, self.h.get_metrics())

    @mock.patch('sonarqube_api.api.requests.Session.post')
    def test_activate_rule(self, mock_post):
        # Missing param key
        resp = mock.MagicMock(status_code=400)
        resp.json.return_value = {
            'errors': [{
                'msg': 'The rule_key parameter is missing'
            }]
        }
        mock_post.return_value = resp
        with self.assertRaises(ValidationError):
            self.h.activate_rule(None,
                                 'py-234454',
                                 reset=True,
                                 severity='MAJOR',
                                 format='^setUp|tearDown$')

        # Check call, params and severity were ignored
        url = self.h._get_url(self.h.RULES_ACTIVATION_ENDPOINT)
        mock_post.assert_called_with(url,
                                     data={
                                         'rule_key': None,
                                         'profile_key': 'py-234454',
                                         'reset': 'true'
                                     })
        mock_post.reset_mock()

        # Now post proper data, with
        resp.status_code = 200
        resp.json.return_value = {'result': 'ok'}
        self.h.activate_rule('py:S1291',
                             'py-234454',
                             format='^setUp|tearDown$')

        # Check call, params and severity added
        mock_post.assert_called_with(url,
                                     data={
                                         'rule_key': 'py:S1291',
                                         'profile_key': 'py-234454',
                                         'reset': 'false',
                                         'params': 'format=^setUp|tearDown$'
                                     })

    @mock.patch('sonarqube_api.api.requests.Session.post')
    def test_create_rule(self, mock_post):
        # Rule exists, error
        resp = mock.MagicMock(status_code=400)
        resp.json.return_value = {'errors': [{'msg': 'rule already exists'}]}
        mock_post.return_value = resp
        with self.assertRaises(ValidationError):
            self.h.create_rule('x1', 'Do not frobnicate',
                               'Frobnicating is wrong and should be avoided',
                               'Reemove forbnication', 'DEFFN/SJS', 'MAJOR',
                               'ACTIVE', 'XPath')

        # Simulate removal, now post is OK
        resp.status_code = 200
        resp.json.return_value = {'result': 'ok'}
        self.h.create_rule('x1', 'Do not frobnicate',
                           'Frobnicating is wrong and should be avoided',
                           'Reemove forbnication', 'DEFFN/SJS', 'major',
                           'active', 'XPath')

        # Check calls
        posted_data = {
            'custom_key': 'x1',
            'name': 'Do not frobnicate',
            'markdown_description':
            'Frobnicating is wrong and should be avoided',
            'params': 'message=Reemove forbnication;xpathQuery=DEFFN/SJS',
            'severity': 'MAJOR',
            'status': 'ACTIVE',
            'template_key': 'XPath'
        }
        url = self.h._get_url(self.h.RULES_CREATE_ENDPOINT)
        mock_post.assert_called_with(url, data=posted_data)

    @mock.patch('sonarqube_api.api.SonarAPIHandler._make_call')
    def test_get_metrics(self, mock_call):
        # Two pages, once each
        resp = mock.MagicMock(status_code=200)
        resp.json.side_effect = [
            {
                'p':
                1,
                'ps':
                2,
                'total':
                3,
                'metrics': [{
                    'project': 'lala',
                    'coverage': 70,
                    'violations': 56
                }, {
                    'project': 'lele',
                    'coverage': 72,
                    'violations': 34
                }]
            },
            {
                'p': 2,
                'ps': 2,
                'total': 3,
                'metrics': [{
                    'project': 'lolo',
                    'coverage': 71,
                    'violations': 23
                }]
            },
        ]
        mock_call.return_value = resp

        # Get metrics with two fields (as list)
        resources = list(self.h.get_metrics(fields=['coverage', 'violations']))
        self.assertEqual(resources, [{
            'project': 'lala',
            'coverage': 70,
            'violations': 56
        }, {
            'project': 'lele',
            'coverage': 72,
            'violations': 34
        }, {
            'project': 'lolo',
            'coverage': 71,
            'violations': 23
        }])

        # Ensure make_call was called twice with correct params
        self.assertEqual(mock_call.call_count, 2)
        mock_call.assert_any_call('get',
                                  self.h.METRICS_LIST_ENDPOINT,
                                  f='coverage,violations')
        mock_call.assert_any_call('get',
                                  self.h.METRICS_LIST_ENDPOINT,
                                  f='coverage,violations',
                                  p=2)

    @mock.patch('sonarqube_api.api.SonarAPIHandler._make_call')
    def test_get_rules(self, mock_call):
        # Two pages, once each
        resp = mock.MagicMock(status_code=200)
        resp.json.side_effect = [
            {
                'p': 1,
                'ps': 2,
                'total': 3,
                'rules': [{
                    'key': 'lala'
                }, {
                    'key': 'lele'
                }]
            },
            {
                'p': 2,
                'ps': 2,
                'total': 3,
                'rules': [{
                    'key': 'lolo'
                }]
            },
        ]
        mock_call.return_value = resp

        # Get metrics with two fields (as list)
        resources = list(
            self.h.get_rules(profile='prof1', languages=['py', 'js']))
        self.assertEqual(resources, [{
            'key': 'lala'
        }, {
            'key': 'lele'
        }, {
            'key': 'lolo'
        }])

        # Ensure make_call was called twice with correct params
        self.assertEqual(mock_call.call_count, 2)
        mock_call.assert_any_call('get',
                                  self.h.RULES_LIST_ENDPOINT,
                                  is_template='no',
                                  statuses='READY',
                                  activation='true',
                                  qprofile='prof1',
                                  languages='py,js')
        mock_call.assert_any_call('get',
                                  self.h.RULES_LIST_ENDPOINT,
                                  is_template='no',
                                  statuses='READY',
                                  activation='true',
                                  qprofile='prof1',
                                  languages='py,js',
                                  p=2)

    @mock.patch('sonarqube_api.api.SonarAPIHandler._make_call')
    def test_get_resources_metrics(self, mock_call):
        # Note: resource metrics responses are not paged
        resp = mock.MagicMock(status_code=200)
        resp.json.return_value = [{
            'name':
            'lala',
            'key':
            'wow:lala',
            'scope':
            'PRJ',
            'msr': [{
                'key': 'coverage',
                'val': 26.0,
                'frmt_val': '26.0%'
            }]
        }, {
            'name':
            'lele',
            'key':
            'wow:lele',
            'scope':
            'PRJ',
            'msr': [{
                'key': 'coverage',
                'val': 29.0,
                'frmt_val': '29.0%'
            }]
        }]
        mock_call.return_value = resp

        # Get metrics without specifying resource and no trends
        resources = list(self.h.get_resources_metrics())
        self.assertEqual(
            resources,
            [{
                'name': 'lala',
                'key': 'wow:lala',
                'scope': 'PRJ',
                'msr': [{
                    'key': 'coverage',
                    'val': 26.0,
                    'frmt_val': '26.0%'
                }]
            }, {
                'name': 'lele',
                'key': 'wow:lele',
                'scope': 'PRJ',
                'msr': [{
                    'key': 'coverage',
                    'val': 29.0,
                    'frmt_val': '29.0%'
                }]
            }])

        # Ensure make_call was called once with correct params
        mock_call.assert_called_once_with('get',
                                          self.h.RESOURCES_ENDPOINT,
                                          metrics=','.join(
                                              self.h.GENERAL_METRICS))
        mock_call.reset_mock()

        # Now get one resource, with metrics and trends
        resp.json.return_value = [{
            'name':
            'lala',
            'key':
            'wow:lala',
            'scope':
            'PRJ',
            'msr': [{
                'key': 'coverage',
                'val': 26.0,
                'frmt_val': '26.0%'
            }]
        }]
        resources = list(
            self.h.get_resources_metrics(resource='wow:lala',
                                         metrics=['coverage'],
                                         include_trends=True))
        self.assertEqual(
            resources,
            [{
                'name': 'lala',
                'key': 'wow:lala',
                'scope': 'PRJ',
                'msr': [{
                    'key': 'coverage',
                    'val': 26.0,
                    'frmt_val': '26.0%'
                }]
            }])

        # Check call
        mock_call.assert_called_once_with(
            'get',
            self.h.RESOURCES_ENDPOINT,
            resource='wow:lala',
            includetrends='true',
            metrics=','.join(['coverage'] + list(self.h.NEW_METRICS)))

    @mock.patch('sonarqube_api.api.SonarAPIHandler._make_call')
    def test_get_resources_debt(self, mock_call):
        # Note: resource metrics responses are not paged
        resp = mock.MagicMock(status_code=200)
        resp.json.return_value = [{
            'key':
            'wow:wtf',
            'name':
            'Wizardly Table Fetching',
            'scope':
            'PRJ',
            'msr': [{
                'ctic_key': 'TESTABILITY',
                'ctic_name': 'Testability',
                'val': 121710.0,
                'key': 'sqale_index',
                'frmt_val': '253d'
            }, {
                'ctic_key': 'MAINTAINABILITY',
                'ctic_name': 'Maintainability',
                'val': 56916.0,
                'key': 'sqale_index',
                'frmt_val': '118d'
            }]
        }]
        mock_call.return_value = resp

        # Get debts for testability
        resources = list(
            self.h.get_resources_debt(
                resource='wow:wtf',
                categories=['testability', 'maintainability']))
        self.assertEqual(resources, [{
            'key':
            'wow:wtf',
            'name':
            'Wizardly Table Fetching',
            'scope':
            'PRJ',
            'msr': [{
                'ctic_key': 'TESTABILITY',
                'ctic_name': 'Testability',
                'val': 121710.0,
                'key': 'sqale_index',
                'frmt_val': '253d'
            }, {
                'ctic_key': 'MAINTAINABILITY',
                'ctic_name': 'Maintainability',
                'val': 56916.0,
                'key': 'sqale_index',
                'frmt_val': '118d'
            }]
        }])

        # Ensure make_call was called once with correct params
        mock_call.assert_called_once_with(
            'get',
            self.h.RESOURCES_ENDPOINT,
            resource='wow:wtf',
            model='SQALE',
            metrics='sqale_index',
            characteristics='TESTABILITY,MAINTAINABILITY')
        mock_call.reset_mock()

    @mock.patch('sonarqube_api.api.SonarAPIHandler._make_call')
    def test_get_resources_full_data(self, mock_call):
        # Setup responses for calls
        resp = mock.MagicMock(status_code=200)
        resp.json.side_effect = [
            # First call: get metrics
            [{
                'name': 'Wizardly Table Fetching',
                'key': 'wow:wtf',
                'scope': 'PRJ',
                'msr': [{
                    'key': 'coverage',
                    'val': 26.0,
                    'frmt_val': '26.0%'
                }]
            }],
            # Second call: get debt (with wrong name)
            [{
                'key':
                'wow:wtf',
                'name':
                'WTFdudeWrongName',
                'scope':
                'PRJ',
                'msr': [{
                    'ctic_key': 'TESTABILITY',
                    'ctic_name': 'Testability',
                    'val': 121710.0,
                    'key': 'sqale_index',
                    'frmt_val': '253d'
                }, {
                    'ctic_key': 'MAINTAINABILITY',
                    'ctic_name': 'Maintainability',
                    'val': 56916.0,
                    'key': 'sqale_index',
                    'frmt_val': '118d'
                }]
            }]
        ]
        mock_call.return_value = resp

        # Make the call with one metric and two debt categories
        resources = list(
            self.h.get_resources_full_data(
                resource='wow:wtf',
                metrics=['coverage'],
                categories=['testability', 'maintainability']))

        # Ensure proper merge of data and first name is kept
        self.assertEqual(resources, [{
            'name':
            'Wizardly Table Fetching',
            'key':
            'wow:wtf',
            'scope':
            'PRJ',
            'msr': [{
                'key': 'coverage',
                'val': 26.0,
                'frmt_val': '26.0%'
            }, {
                'ctic_key': 'TESTABILITY',
                'ctic_name': 'Testability',
                'val': 121710.0,
                'key': 'sqale_index',
                'frmt_val': '253d'
            }, {
                'ctic_key': 'MAINTAINABILITY',
                'ctic_name': 'Maintainability',
                'val': 56916.0,
                'key': 'sqale_index',
                'frmt_val': '118d'
            }]
        }])

        # Ensure make_call was called twice with correct params
        # Note: do not use mock_calls or assert_has_calls or you'll get weird results, the list
        # contains ONLY a call that mas never made (p: 3) twice
        self.assertEqual(mock_call.call_count, 2)
        mock_call.assert_any_call('get',
                                  self.h.RESOURCES_ENDPOINT,
                                  resource='wow:wtf',
                                  metrics='coverage')
        mock_call.assert_any_call(
            'get',
            self.h.RESOURCES_ENDPOINT,
            resource='wow:wtf',
            model='SQALE',
            metrics='sqale_index',
            characteristics='TESTABILITY,MAINTAINABILITY')
 def setUp(self):
     self.h = SonarAPIHandler(user="******", password="******")
class SonarAPIHandlerTest(TestCase):
    def setUp(self):
        self.h = SonarAPIHandler(user="******", password="******")

    def test_url_building(self):
        test = SonarAPIHandler(host="http://localhost", port=9001, base_path="/testing")
        self.assertEqual(
            "http://*****:*****@mock.patch("sonarqube_api.api.requests.Session.get")
    def test_validate_auth(self, mock_res):
        resp = mock.MagicMock(status_code=200)
        mock_res.return_value = resp

        # Error, not authenticated
        resp.json.return_value = {"valid": False}
        self.assertFalse(self.h.validate_authentication())

        # Weird result, always assume invalid
        resp.json.return_value = {"wtf": "lala"}
        self.assertFalse(self.h.validate_authentication())

        # OK, authenticated
        resp.json.return_value = {"valid": True}
        self.assertTrue(self.h.validate_authentication())

    @mock.patch("sonarqube_api.api.requests.Session.get")
    def test_errors(self, mock_get):
        # Empty response , cannot get next
        resp = mock.MagicMock(status_code=200)
        resp.json.return_value = {"p": 1, "ps": 20, "total": 0, "metrics": []}
        mock_get.return_value = resp
        self.assertRaises(StopIteration, next, self.h.get_metrics())

        # Invalid data, raises ValidationError
        resp.status_code = 400
        resp.json.return_value = {"errors": [{"msg": "invalid data for field"}]}
        self.assertRaises(ValidationError, next, self.h.get_metrics())

        # Not authenticated, raises AuthError
        resp.status_code = 401
        resp.reason = "Unauthorized"
        self.assertRaises(AuthError, next, self.h.get_metrics())

        # Not authorized, raises AuthError
        resp.status_code = 403
        resp.reason = "Forbidden"
        self.assertRaises(AuthError, next, self.h.get_metrics())

        # Not found, generic client error
        resp.status_code = 404
        resp.reason = "Not Found"
        self.assertRaises(ClientError, next, self.h.get_metrics())

        # Server error
        resp.status_code = 500
        resp.reason = "Internal Server Error"
        self.assertRaises(ServerError, next, self.h.get_metrics())

    @mock.patch("sonarqube_api.api.requests.Session.post")
    def test_activate_rule(self, mock_post):
        # Missing param key
        resp = mock.MagicMock(status_code=400)
        resp.json.return_value = {"errors": [{"msg": "The rule_key parameter is missing"}]}
        mock_post.return_value = resp
        with self.assertRaises(ValidationError):
            self.h.activate_rule(None, "py-234454", reset=True, severity="MAJOR", format="^setUp|tearDown$")

        # Check call, params and severity were ignored
        url = self.h._get_url(self.h.RULES_ACTIVATION_ENDPOINT)
        mock_post.assert_called_with(url, data={"rule_key": None, "profile_key": "py-234454", "reset": "true"})
        mock_post.reset_mock()

        # Now post proper data, with
        resp.status_code = 200
        resp.json.return_value = {"result": "ok"}
        self.h.activate_rule("py:S1291", "py-234454", format="^setUp|tearDown$")

        # Check call, params and severity added
        mock_post.assert_called_with(
            url,
            data={
                "rule_key": "py:S1291",
                "profile_key": "py-234454",
                "reset": "false",
                "params": "format=^setUp|tearDown$",
            },
        )

    @mock.patch("sonarqube_api.api.requests.Session.post")
    def test_create_rule(self, mock_post):
        # Rule exists, error
        resp = mock.MagicMock(status_code=400)
        resp.json.return_value = {"errors": [{"msg": "rule already exists"}]}
        mock_post.return_value = resp
        with self.assertRaises(ValidationError):
            self.h.create_rule(
                "x1",
                "Do not frobnicate",
                "Frobnicating is wrong and should be avoided",
                "Reemove forbnication",
                "DEFFN/SJS",
                "MAJOR",
                "ACTIVE",
                "XPath",
            )

        # Simulate removal, now post is OK
        resp.status_code = 200
        resp.json.return_value = {"result": "ok"}
        self.h.create_rule(
            "x1",
            "Do not frobnicate",
            "Frobnicating is wrong and should be avoided",
            "Reemove forbnication",
            "DEFFN/SJS",
            "major",
            "active",
            "XPath",
        )

        # Check calls
        posted_data = {
            "custom_key": "x1",
            "name": "Do not frobnicate",
            "markdown_description": "Frobnicating is wrong and should be avoided",
            "params": "message=Reemove forbnication;xpathQuery=DEFFN/SJS",
            "severity": "MAJOR",
            "status": "ACTIVE",
            "template_key": "XPath",
        }
        url = self.h._get_url(self.h.RULES_CREATE_ENDPOINT)
        mock_post.assert_called_with(url, data=posted_data)

    @mock.patch("sonarqube_api.api.SonarAPIHandler._make_call")
    def test_get_metrics(self, mock_call):
        # Two pages, once each
        resp = mock.MagicMock(status_code=200)
        resp.json.side_effect = [
            {
                "p": 1,
                "ps": 2,
                "total": 3,
                "metrics": [
                    {"project": "lala", "coverage": 70, "violations": 56},
                    {"project": "lele", "coverage": 72, "violations": 34},
                ],
            },
            {"p": 2, "ps": 2, "total": 3, "metrics": [{"project": "lolo", "coverage": 71, "violations": 23}]},
        ]
        mock_call.return_value = resp

        # Get metrics with two fields (as list)
        resources = list(self.h.get_metrics(fields=["coverage", "violations"]))
        self.assertEqual(
            resources,
            [
                {"project": "lala", "coverage": 70, "violations": 56},
                {"project": "lele", "coverage": 72, "violations": 34},
                {"project": "lolo", "coverage": 71, "violations": 23},
            ],
        )

        # Ensure make_call was called twice with correct params
        self.assertEqual(mock_call.call_count, 2)
        mock_call.assert_any_call("get", self.h.METRICS_LIST_ENDPOINT, f="coverage,violations")
        mock_call.assert_any_call("get", self.h.METRICS_LIST_ENDPOINT, f="coverage,violations", p=2)

    @mock.patch("sonarqube_api.api.SonarAPIHandler._make_call")
    def test_get_rules(self, mock_call):
        # Two pages, once each
        resp = mock.MagicMock(status_code=200)
        resp.json.side_effect = [
            {"p": 1, "ps": 2, "total": 3, "rules": [{"key": "lala"}, {"key": "lele"}]},
            {"p": 2, "ps": 2, "total": 3, "rules": [{"key": "lolo"}]},
        ]
        mock_call.return_value = resp

        # Get metrics with two fields (as list)
        resources = list(self.h.get_rules(profile="prof1", languages=["py", "js"]))
        self.assertEqual(resources, [{"key": "lala"}, {"key": "lele"}, {"key": "lolo"}])

        # Ensure make_call was called twice with correct params
        self.assertEqual(mock_call.call_count, 2)
        mock_call.assert_any_call(
            "get",
            self.h.RULES_LIST_ENDPOINT,
            is_template="no",
            statuses="READY",
            activation="true",
            qprofile="prof1",
            languages="py,js",
        )
        mock_call.assert_any_call(
            "get",
            self.h.RULES_LIST_ENDPOINT,
            is_template="no",
            statuses="READY",
            activation="true",
            qprofile="prof1",
            languages="py,js",
            p=2,
        )

    @mock.patch("sonarqube_api.api.SonarAPIHandler._make_call")
    def test_get_resources_metrics(self, mock_call):
        # Note: resource metrics responses are not paged
        resp = mock.MagicMock(status_code=200)
        resp.json.return_value = [
            {
                "name": "lala",
                "key": "wow:lala",
                "scope": "PRJ",
                "msr": [{"key": "coverage", "val": 26.0, "frmt_val": "26.0%"}],
            },
            {
                "name": "lele",
                "key": "wow:lele",
                "scope": "PRJ",
                "msr": [{"key": "coverage", "val": 29.0, "frmt_val": "29.0%"}],
            },
        ]
        mock_call.return_value = resp

        # Get metrics without specifying resource and no trends
        resources = list(self.h.get_resources_metrics())
        self.assertEqual(
            resources,
            [
                {
                    "name": "lala",
                    "key": "wow:lala",
                    "scope": "PRJ",
                    "msr": [{"key": "coverage", "val": 26.0, "frmt_val": "26.0%"}],
                },
                {
                    "name": "lele",
                    "key": "wow:lele",
                    "scope": "PRJ",
                    "msr": [{"key": "coverage", "val": 29.0, "frmt_val": "29.0%"}],
                },
            ],
        )

        # Ensure make_call was called once with correct params
        mock_call.assert_called_once_with("get", self.h.RESOURCES_ENDPOINT, metrics=",".join(self.h.GENERAL_METRICS))
        mock_call.reset_mock()

        # Now get one resource, with metrics and trends
        resp.json.return_value = [
            {
                "name": "lala",
                "key": "wow:lala",
                "scope": "PRJ",
                "msr": [{"key": "coverage", "val": 26.0, "frmt_val": "26.0%"}],
            }
        ]
        resources = list(
            self.h.get_resources_metrics(
                resource="wow:lala", metrics=["coverage"], include_trends=True, include_modules=True
            )
        )
        self.assertEqual(
            resources,
            [
                {
                    "name": "lala",
                    "key": "wow:lala",
                    "scope": "PRJ",
                    "msr": [{"key": "coverage", "val": 26.0, "frmt_val": "26.0%"}],
                }
            ],
        )

        # Check call
        mock_call.assert_called_once_with(
            "get",
            self.h.RESOURCES_ENDPOINT,
            resource="wow:lala",
            includetrends="true",
            metrics="coverage,new_coverage",
            qualifiers="TRK,BRC",
        )

    @mock.patch("sonarqube_api.api.SonarAPIHandler._make_call")
    def test_get_resources_debt(self, mock_call):
        # Note: resource metrics responses are not paged
        resp = mock.MagicMock(status_code=200)
        resp.json.return_value = [
            {
                "key": "wow:wtf",
                "name": "Wizardly Table Fetching",
                "scope": "PRJ",
                "msr": [
                    {
                        "ctic_key": "TESTABILITY",
                        "ctic_name": "Testability",
                        "val": 121710.0,
                        "key": "sqale_index",
                        "frmt_val": "253d",
                    },
                    {
                        "ctic_key": "MAINTAINABILITY",
                        "ctic_name": "Maintainability",
                        "val": 56916.0,
                        "key": "sqale_index",
                        "frmt_val": "118d",
                    },
                ],
            }
        ]
        mock_call.return_value = resp

        # Get debts for testability
        resources = list(
            self.h.get_resources_debt(
                resource="wow:wtf",
                categories=["testability", "maintainability"],
                include_trends=True,
                include_modules=True,
            )
        )
        self.assertEqual(
            resources,
            [
                {
                    "key": "wow:wtf",
                    "name": "Wizardly Table Fetching",
                    "scope": "PRJ",
                    "msr": [
                        {
                            "ctic_key": "TESTABILITY",
                            "ctic_name": "Testability",
                            "val": 121710.0,
                            "key": "sqale_index",
                            "frmt_val": "253d",
                        },
                        {
                            "ctic_key": "MAINTAINABILITY",
                            "ctic_name": "Maintainability",
                            "val": 56916.0,
                            "key": "sqale_index",
                            "frmt_val": "118d",
                        },
                    ],
                }
            ],
        )

        # Ensure make_call was called once with correct params
        mock_call.assert_called_once_with(
            "get",
            self.h.RESOURCES_ENDPOINT,
            resource="wow:wtf",
            model="SQALE",
            metrics="sqale_index",
            characteristics="TESTABILITY,MAINTAINABILITY",
            includetrends="true",
            qualifiers="TRK,BRC",
        )
        mock_call.reset_mock()

    @mock.patch("sonarqube_api.api.SonarAPIHandler._make_call")
    def test_get_resources_full_data(self, mock_call):
        # Setup responses for calls
        resp = mock.MagicMock(status_code=200)
        resp.json.side_effect = [
            # First call: get metrics
            [
                {
                    "name": "Wizardly Table Fetching",
                    "key": "wow:wtf",
                    "scope": "PRJ",
                    "msr": [{"key": "coverage", "val": 26.0, "frmt_val": "26.0%"}],
                }
            ],
            # Second call: get debt (with wrong name) and a new project
            [
                {
                    "key": "wow:wtf",
                    "name": "WTFdudeWrongName",
                    "scope": "PRJ",
                    "msr": [
                        {
                            "ctic_key": "TESTABILITY",
                            "ctic_name": "Testability",
                            "val": 121710.0,
                            "key": "sqale_index",
                            "frmt_val": "253d",
                        },
                        {
                            "ctic_key": "MAINTAINABILITY",
                            "ctic_name": "Maintainability",
                            "val": 56916.0,
                            "key": "sqale_index",
                            "frmt_val": "118d",
                        },
                    ],
                },
                {
                    "key": "lol:hahaha",
                    "name": "Another project",
                    "scope": "PRJ",
                    "msr": [
                        {
                            "ctic_key": "TESTABILITY",
                            "ctic_name": "Testability",
                            "val": 126.0,
                            "key": "sqale_index",
                            "frmt_val": "2h 6m",
                        },
                        {
                            "ctic_key": "MAINTAINABILITY",
                            "ctic_name": "Maintainability",
                            "val": 12.0,
                            "key": "sqale_index",
                            "frmt_val": "12m",
                        },
                    ],
                },
            ],
        ]
        mock_call.return_value = resp

        # Make the call with one metric and two debt categories
        resources = list(
            self.h.get_resources_full_data(
                metrics=["coverage"], categories=["testability", "maintainability"], include_modules=True
            )
        )

        # Ensure proper merge of data, first name use and sorting
        self.assertEqual(
            resources,
            [
                {
                    "key": "lol:hahaha",
                    "name": "Another project",
                    "scope": "PRJ",
                    "msr": [
                        {
                            "ctic_key": "TESTABILITY",
                            "ctic_name": "Testability",
                            "val": 126.0,
                            "key": "sqale_index",
                            "frmt_val": "2h 6m",
                        },
                        {
                            "ctic_key": "MAINTAINABILITY",
                            "ctic_name": "Maintainability",
                            "val": 12.0,
                            "key": "sqale_index",
                            "frmt_val": "12m",
                        },
                    ],
                },
                {
                    "name": "Wizardly Table Fetching",
                    "key": "wow:wtf",
                    "scope": "PRJ",
                    "msr": [
                        {"key": "coverage", "val": 26.0, "frmt_val": "26.0%"},
                        {
                            "ctic_key": "TESTABILITY",
                            "ctic_name": "Testability",
                            "val": 121710.0,
                            "key": "sqale_index",
                            "frmt_val": "253d",
                        },
                        {
                            "ctic_key": "MAINTAINABILITY",
                            "ctic_name": "Maintainability",
                            "val": 56916.0,
                            "key": "sqale_index",
                            "frmt_val": "118d",
                        },
                    ],
                },
            ],
        )

        # Ensure make_call was called twice with correct params
        # Note: do not use mock_calls or assert_has_calls or you'll get weird results, the list
        # contains ONLY a call that mas never made (p: 3) twice
        self.assertEqual(mock_call.call_count, 2)
        mock_call.assert_any_call("get", self.h.RESOURCES_ENDPOINT, metrics="coverage", qualifiers="TRK,BRC")
        mock_call.assert_any_call(
            "get",
            self.h.RESOURCES_ENDPOINT,
            model="SQALE",
            metrics="sqale_index",
            characteristics="TESTABILITY,MAINTAINABILITY",
            qualifiers="TRK,BRC",
        )
 def setUp(self):
     self.h = SonarAPIHandler(user='******', password='******')
class SonarAPIHandlerTest(TestCase):

    def setUp(self):
        self.h = SonarAPIHandler(user='******', password='******')

    @mock.patch('sonarqube_api.api.requests.Session.get')
    def test_validate_auth(self, mock_res):
        resp = mock.MagicMock(status_code=200)
        mock_res.return_value = resp

        # Error, not authenticated
        resp.json.return_value = {'valid': False}
        self.assertFalse(self.h.validate_authentication())

        # Weird result, always assume invalid
        resp.json.return_value = {'wtf': 'lala'}
        self.assertFalse(self.h.validate_authentication())

        # OK, authenticated
        resp.json.return_value = {'valid': True}
        self.assertTrue(self.h.validate_authentication())

    @mock.patch('sonarqube_api.api.requests.Session.get')
    def test_errors(self, mock_get):
        # Empty response , cannot get next
        resp = mock.MagicMock(status_code=200)
        resp.json.return_value = {'p': 1, 'ps': 20, 'total': 0, 'metrics': []}
        mock_get.return_value = resp
        self.assertRaises(StopIteration, next, self.h.get_metrics())

        # Invalid data, raises ValidationError
        resp.status_code = 400
        resp.json.return_value = {'errors': [{'msg': 'invalid data for field'}]}
        self.assertRaises(ValidationError, next, self.h.get_metrics())

        # Not authenticated, raises AuthError
        resp.status_code = 401
        resp.reason = 'Unauthorized'
        self.assertRaises(AuthError, next, self.h.get_metrics())

        # Not authorized, raises AuthError
        resp.status_code = 403
        resp.reason = 'Forbidden'
        self.assertRaises(AuthError, next, self.h.get_metrics())

        # Not found, generic client error
        resp.status_code = 404
        resp.reason = 'Not Found'
        self.assertRaises(ClientError, next, self.h.get_metrics())

        # Server error
        resp.status_code = 500
        resp.reason = 'Internal Server Error'
        self.assertRaises(ServerError, next, self.h.get_metrics())

    @mock.patch('sonarqube_api.api.requests.Session.post')
    def test_activate_rule(self, mock_post):
        # Missing param key
        resp = mock.MagicMock(status_code=400)
        resp.json.return_value = {'errors': [{'msg': 'The rule_key parameter is missing'}]}
        mock_post.return_value = resp
        with self.assertRaises(ValidationError):
            self.h.activate_rule(None, 'py-234454', reset=True, severity='MAJOR', format='^setUp|tearDown$')

        # Check call, params and severity were ignored
        url = self.h._get_url(self.h.RULES_ACTIVATION_ENDPOINT)
        mock_post.assert_called_with(url, data={'rule_key': None, 'profile_key': 'py-234454', 'reset': 'true'})
        mock_post.reset_mock()

        # Now post proper data, with
        resp.status_code = 200
        resp.json.return_value = {'result': 'ok'}
        self.h.activate_rule('py:S1291', 'py-234454', format='^setUp|tearDown$')

        # Check call, params and severity added
        mock_post.assert_called_with(url, data={'rule_key': 'py:S1291', 'profile_key': 'py-234454',
                                                'reset': 'false', 'params': 'format=^setUp|tearDown$'})

    @mock.patch('sonarqube_api.api.requests.Session.post')
    def test_create_rule(self, mock_post):
        # Rule exists, error
        resp = mock.MagicMock(status_code=400)
        resp.json.return_value = {'errors': [{'msg': 'rule already exists'}]}
        mock_post.return_value = resp
        with self.assertRaises(ValidationError):
            self.h.create_rule('x1', 'Do not frobnicate', 'Frobnicating is wrong and should be avoided',
                               'Reemove forbnication', 'DEFFN/SJS', 'MAJOR', 'ACTIVE', 'XPath')

        # Simulate removal, now post is OK
        resp.status_code = 200
        resp.json.return_value = {'result': 'ok'}
        self.h.create_rule('x1', 'Do not frobnicate', 'Frobnicating is wrong and should be avoided',
                           'Reemove forbnication', 'DEFFN/SJS', 'major', 'active', 'XPath')

        # Check calls
        posted_data = {
            'custom_key': 'x1', 'name': 'Do not frobnicate',
            'markdown_description': 'Frobnicating is wrong and should be avoided',
            'params': 'message=Reemove forbnication;xpathQuery=DEFFN/SJS',
            'severity': 'MAJOR', 'status': 'ACTIVE', 'template_key': 'XPath'
        }
        url = self.h._get_url(self.h.RULES_CREATE_ENDPOINT)
        mock_post.assert_called_with(url, data=posted_data)

    @mock.patch('sonarqube_api.api.SonarAPIHandler._make_call')
    def test_get_metrics(self, mock_call):
        # Two pages, once each
        resp = mock.MagicMock(status_code=200)
        resp.json.side_effect = [
            {'p': 1, 'ps': 2, 'total': 3, 'metrics': [{'project': 'lala', 'coverage': 70, 'violations': 56},
                                                      {'project': 'lele', 'coverage': 72, 'violations': 34}]},
            {'p': 2, 'ps': 2, 'total': 3, 'metrics': [{'project': 'lolo', 'coverage': 71, 'violations': 23}]},
        ]
        mock_call.return_value = resp

        # Get metrics with two fields (as list)
        resources = list(self.h.get_metrics(fields=['coverage', 'violations']))
        self.assertEqual(resources, [{'project': 'lala', 'coverage': 70, 'violations': 56},
                                     {'project': 'lele', 'coverage': 72, 'violations': 34},
                                     {'project': 'lolo', 'coverage': 71, 'violations': 23}])

        # Ensure make_call was called twice with correct params
        self.assertEqual(mock_call.call_count, 2)
        mock_call.assert_any_call(
            'get', self.h.METRICS_LIST_ENDPOINT, f='coverage,violations'
        )
        mock_call.assert_any_call(
            'get', self.h.METRICS_LIST_ENDPOINT, f='coverage,violations', p=2
        )

    @mock.patch('sonarqube_api.api.SonarAPIHandler._make_call')
    def test_get_rules(self, mock_call):
        # Two pages, once each
        resp = mock.MagicMock(status_code=200)
        resp.json.side_effect = [
            {'p': 1, 'ps': 2, 'total': 3, 'rules': [{'key': 'lala'}, {'key': 'lele'}]},
            {'p': 2, 'ps': 2, 'total': 3, 'rules': [{'key': 'lolo'}]},
        ]
        mock_call.return_value = resp

        # Get metrics with two fields (as list)
        resources = list(self.h.get_rules(profile='prof1', languages=['py', 'js']))
        self.assertEqual(resources, [{'key': 'lala'}, {'key': 'lele'}, {'key': 'lolo'}])

        # Ensure make_call was called twice with correct params
        self.assertEqual(mock_call.call_count, 2)
        mock_call.assert_any_call(
            'get', self.h.RULES_LIST_ENDPOINT, is_template='no', statuses='READY',
            activation='true', qprofile='prof1', languages='py,js'
        )
        mock_call.assert_any_call(
            'get', self.h.RULES_LIST_ENDPOINT, is_template='no', statuses='READY',
            activation='true', qprofile='prof1', languages='py,js', p=2
        )

    @mock.patch('sonarqube_api.api.SonarAPIHandler._make_call')
    def test_get_resources_metrics(self, mock_call):
        # Note: resource metrics responses are not paged
        resp = mock.MagicMock(status_code=200)
        resp.json.return_value = [
            {'name': 'lala', 'key': 'wow:lala', 'scope': 'PRJ',
             'msr': [{'key': 'coverage', 'val': 26.0, 'frmt_val': '26.0%'}]},
            {'name': 'lele', 'key': 'wow:lele', 'scope': 'PRJ',
             'msr': [{'key': 'coverage', 'val': 29.0, 'frmt_val': '29.0%'}]}
        ]
        mock_call.return_value = resp

        # Get metrics without specifying resource and no trends
        resources = list(self.h.get_resources_metrics())
        self.assertEqual(resources, [
            {'name': 'lala', 'key': 'wow:lala', 'scope': 'PRJ',
             'msr': [{'key': 'coverage', 'val': 26.0, 'frmt_val': '26.0%'}]},
            {'name': 'lele', 'key': 'wow:lele', 'scope': 'PRJ',
             'msr': [{'key': 'coverage', 'val': 29.0, 'frmt_val': '29.0%'}]}
        ])

        # Ensure make_call was called once with correct params
        mock_call.assert_called_once_with(
            'get', self.h.RESOURCES_ENDPOINT,
            metrics=','.join(self.h.GENERAL_METRICS)
        )
        mock_call.reset_mock()

        # Now get one resource, with metrics and trends
        resp.json.return_value = [
            {'name': 'lala', 'key': 'wow:lala', 'scope': 'PRJ',
             'msr': [{'key': 'coverage', 'val': 26.0, 'frmt_val': '26.0%'}]}
        ]
        resources = list(self.h.get_resources_metrics(
            resource='wow:lala', metrics=['coverage'], include_trends=True
        ))
        self.assertEqual(resources, [
            {'name': 'lala', 'key': 'wow:lala', 'scope': 'PRJ',
             'msr': [{'key': 'coverage', 'val': 26.0, 'frmt_val': '26.0%'}]}
        ])

        # Check call
        mock_call.assert_called_once_with(
            'get', self.h.RESOURCES_ENDPOINT,
            resource='wow:lala', includetrends='true',
            metrics='coverage,new_coverage'
        )

    @mock.patch('sonarqube_api.api.SonarAPIHandler._make_call')
    def test_get_resources_debt(self, mock_call):
        # Note: resource metrics responses are not paged
        resp = mock.MagicMock(status_code=200)
        resp.json.return_value = [
            {'key': 'wow:wtf', 'name': 'Wizardly Table Fetching', 'scope': 'PRJ',
             'msr': [{'ctic_key': 'TESTABILITY', 'ctic_name': 'Testability',
                      'val': 121710.0, 'key': 'sqale_index', 'frmt_val': '253d'},
                     {'ctic_key': 'MAINTAINABILITY', 'ctic_name': 'Maintainability',
                      'val': 56916.0, 'key': 'sqale_index', 'frmt_val': '118d'}]}
        ]
        mock_call.return_value = resp

        # Get debts for testability
        resources = list(self.h.get_resources_debt(
            resource='wow:wtf', categories=['testability', 'maintainability'],
            include_trends=True
        ))
        self.assertEqual(resources, [
            {'key': 'wow:wtf', 'name': 'Wizardly Table Fetching', 'scope': 'PRJ',
             'msr': [{'ctic_key': 'TESTABILITY', 'ctic_name': 'Testability',
                      'val': 121710.0, 'key': 'sqale_index', 'frmt_val': '253d'},
                     {'ctic_key': 'MAINTAINABILITY', 'ctic_name': 'Maintainability',
                      'val': 56916.0, 'key': 'sqale_index', 'frmt_val': '118d'}]}
        ])

        # Ensure make_call was called once with correct params
        mock_call.assert_called_once_with(
            'get', self.h.RESOURCES_ENDPOINT,
            resource='wow:wtf', model='SQALE', metrics='sqale_index',
            characteristics='TESTABILITY,MAINTAINABILITY', includetrends='true'
        )
        mock_call.reset_mock()

    @mock.patch('sonarqube_api.api.SonarAPIHandler._make_call')
    def test_get_resources_full_data(self, mock_call):
        # Setup responses for calls
        resp = mock.MagicMock(status_code=200)
        resp.json.side_effect = [
            # First call: get metrics
            [{'name': 'Wizardly Table Fetching', 'key': 'wow:wtf', 'scope': 'PRJ',
              'msr': [{'key': 'coverage', 'val': 26.0, 'frmt_val': '26.0%'}]}],
            # Second call: get debt (with wrong name)
            [{'key': 'wow:wtf', 'name': 'WTFdudeWrongName', 'scope': 'PRJ',
              'msr': [{'ctic_key': 'TESTABILITY', 'ctic_name': 'Testability',
                       'val': 121710.0, 'key': 'sqale_index', 'frmt_val': '253d'},
                      {'ctic_key': 'MAINTAINABILITY', 'ctic_name': 'Maintainability',
                       'val': 56916.0, 'key': 'sqale_index', 'frmt_val': '118d'}]}]
        ]
        mock_call.return_value = resp

        # Make the call with one metric and two debt categories
        resources = list(self.h.get_resources_full_data(
            resource='wow:wtf', metrics=['coverage'],
            categories=['testability', 'maintainability']
        ))

        # Ensure proper merge of data and first name is kept
        self.assertEqual(resources, [
            {'name': 'Wizardly Table Fetching', 'key': 'wow:wtf', 'scope': 'PRJ',
             'msr': [{'key': 'coverage', 'val': 26.0, 'frmt_val': '26.0%'},
                     {'ctic_key': 'TESTABILITY', 'ctic_name': 'Testability',
                      'val': 121710.0, 'key': 'sqale_index', 'frmt_val': '253d'},
                     {'ctic_key': 'MAINTAINABILITY', 'ctic_name': 'Maintainability',
                      'val': 56916.0, 'key': 'sqale_index', 'frmt_val': '118d'}]}
        ])

        # Ensure make_call was called twice with correct params
        # Note: do not use mock_calls or assert_has_calls or you'll get weird results, the list
        # contains ONLY a call that mas never made (p: 3) twice
        self.assertEqual(mock_call.call_count, 2)
        mock_call.assert_any_call(
            'get', self.h.RESOURCES_ENDPOINT,
            resource='wow:wtf', metrics='coverage'
        )
        mock_call.assert_any_call(
            'get', self.h.RESOURCES_ENDPOINT,
            resource='wow:wtf', model='SQALE', metrics='sqale_index',
            characteristics='TESTABILITY,MAINTAINABILITY'
        )
Example #11
0
from sonarqube_api import SonarAPIHandler

h = SonarAPIHandler(host='http://10.1.3.33',
                    port=9000,
                    user='******',
                    password='******')

# gen = h.get_metrics()

gen = h.get_metrics()

print(gen.nex())

# while True:
#     print(gen.send(None))
class TestGroups(TestCase):
    def setUp(self):
        self.sonar = SonarAPIHandler(user='******', password='******')
        username = str(uuid.uuid1())
        self.test_user = self.sonar.create_user(
            username,
            'qwerty',
            username,
            "{}@example.com".format(username)
        ).json().get('user')

    def test_get_groups(self):
        groups = self.sonar.get_groups().json()
        self.assertIn('groups', groups)

    def test_create_update_delete_group(self):
        test_group = str(uuid.uuid1())
        res = self.sonar.create_group(test_group).json()
        self.assertIn('group', res)
        res = self.sonar.update_group(gid=res['group']['id'], description="This is test group").json()
        self.assertIn('description', res['group'])
        res = self.sonar.delete_group(name=test_group)
        self.assertEqual(res.status_code, 204)

    def test_add_remove_user_group(self):
        test_group = str(uuid.uuid1())
        res = self.sonar.create_group(test_group).json()
        self.assertIn('group', res)
        res = self.sonar.add_user_group(self.test_user['login'], name=test_group)
        self.assertEqual(res.status_code, 204)
        res = self.sonar.get_group_users(name=test_group).json()
        self.assertIn('users', res)

        with self.assertRaises(ValidationError):
            self.sonar.get_group_users()

        res = self.sonar.remove_user_group(self.test_user['login'], name=test_group)
        self.assertEqual(res.status_code, 204)
 def setUp(self):
     self.sonar = SonarAPIHandler(user='******', password='******')
     self.test_user = str(uuid.uuid1())
Example #14
0
import requests
from sonarqube_api import SonarAPIHandler
from flask import Flask, request
from flask_restful import Resource, Api
from flask_cors import CORS, cross_origin

app = Flask(__name__)
CORS(app)
api = Api(app)

#create an object to call all the api functionalities by providing valid
#user name and password
ref = SonarAPIHandler(user='******',
                      password='******',
                      host='http://10.26.32.107')

#make http-get call to get components('name of the projects','key of the projects', etc.) of all the projects.
comp = ref._make_call(method='get', endpoint='/api/projects/index')
ex_comp = comp.json()


#get all projects listed
class get_project_list(Resource):
    def get(self):
        extract_json = comp.json()
        project = []
        co = 1
        for p in extract_json:
            dict = {}
            dict["Project_Name_" + str(co)] = p['nm']
            co = co + 1