diff --git a/puppetboard/utils.py b/puppetboard/utils.py index d21dcd3..cc9b91c 100644 --- a/puppetboard/utils.py +++ b/puppetboard/utils.py @@ -31,10 +31,13 @@ def get_db_version(puppetdb): ''' ver = () try: - (major, minor, build) = [int(x) for x in - puppetdb.current_version().split('.')] + version = puppetdb.current_version() + (major, minor, build) = [int(x) for x in version.split('.')] ver = (major, minor, build) log.info("PuppetDB Version %d.%d.%d" % (major, minor, build)) + except ValueError as e: + log.error("Unable to determine version from string: '%s'" % version) + ver = (4, 2, 0) except HTTPError as e: log.error(str(e)) except ConnectionError as e: diff --git a/test/test_app.py b/test/test_app.py index d7e957d..7311415 100644 --- a/test/test_app.py +++ b/test/test_app.py @@ -131,6 +131,58 @@ def test_index_all(client, mocker, base_str = 'puppetlabs.puppetdb.population:' query_data = { + 'version': [{'version': '4.2.0'}], + 'mbean': [ + { + 'validate': { + 'data': {'Value': '50'}, + 'checks': { + 'path': '%sname=num-nodes' % base_str + } + } + }, + { + 'validate': { + 'data': {'Value': '60'}, + 'checks': { + 'path': '%sname=num-resources' % base_str + } + } + }, + { + 'validate': { + 'data': {'Value': 60.3}, + 'checks': { + 'path': '%sname=avg-resources-per-node' % base_str + } + } + } + ] + } + dbquery = MockDbQuery(query_data) + mocker.patch.object(app.puppetdb, '_query', side_effect=dbquery.get) + rv = client.get('/%2A/') + + soup = BeautifulSoup(rv.data, 'html.parser') + assert soup.title.contents[0] == 'Puppetboard' + vals = soup.find_all('h1', + {"class": "ui header darkblue no-margin-bottom"}) + + assert len(vals) == 3 + assert vals[0].string == '50' + assert vals[1].string == '60' + assert vals[2].string == ' 60' + + assert rv.status_code == 200 + + +def test_index_all_older_puppetdb(client, mocker, + mock_puppetdb_environments, + mock_puppetdb_default_nodes): + + base_str = 'puppetlabs.puppetdb.population:type=default,' + query_data = { + 'version': [{'version': '3.2.0'}], 'mbean': [ { 'validate': { @@ -269,6 +321,106 @@ def test_radiator_view(client, mocker, assert '10' in total.text +def test_radiator_view_all(client, mocker, + mock_puppetdb_environments, + mock_puppetdb_default_nodes): + base_str = 'puppetlabs.puppetdb.population:' + query_data = { + 'version': [{'version': '4.2.0'}], + 'mbean': [ + { + 'validate': { + 'data': {'Value': '50'}, + 'checks': { + 'path': '%sname=num-nodes' % base_str + } + } + }, + { + 'validate': { + 'data': {'Value': '60'}, + 'checks': { + 'path': '%sname=num-resources' % base_str + } + } + }, + { + 'validate': { + 'data': {'Value': 60.3}, + 'checks': { + 'path': '%sname=avg-resources-per-node' % base_str + } + } + } + ] + } + + dbquery = MockDbQuery(query_data) + + mocker.patch.object(app.puppetdb, '_query', side_effect=dbquery.get) + + rv = client.get('/%2A/radiator') + + assert rv.status_code == 200 + + soup = BeautifulSoup(rv.data, 'html.parser') + assert soup.title.contents[0] == 'Puppetboard' + assert soup.h1 != 'Not Found' + total = soup.find(class_='total') + + assert '50' in total.text + + +def test_radiator_view_all_old_version(client, mocker, + mock_puppetdb_environments, + mock_puppetdb_default_nodes): + base_str = 'puppetlabs.puppetdb.population:type=default,' + query_data = { + 'version': [{'version': '3.2.0'}], + 'mbean': [ + { + 'validate': { + 'data': {'Value': '50'}, + 'checks': { + 'path': '%sname=num-nodes' % base_str + } + } + }, + { + 'validate': { + 'data': {'Value': '60'}, + 'checks': { + 'path': '%sname=num-resources' % base_str + } + } + }, + { + 'validate': { + 'data': {'Value': 60.3}, + 'checks': { + 'path': '%sname=avg-resources-per-node' % base_str + } + } + } + ] + } + + dbquery = MockDbQuery(query_data) + + mocker.patch.object(app.puppetdb, '_query', side_effect=dbquery.get) + + rv = client.get('/%2A/radiator') + + assert rv.status_code == 200 + + soup = BeautifulSoup(rv.data, 'html.parser') + assert soup.title.contents[0] == 'Puppetboard' + assert soup.h1 != 'Not Found' + total = soup.find(class_='total') + + assert '50' in total.text + + def test_radiator_view_json(client, mocker, mock_puppetdb_environments, mock_puppetdb_default_nodes): diff --git a/test/test_utils.py b/test/test_utils.py index 5974537..e8e6de2 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -68,6 +68,18 @@ def mock_log(mocker): return mocker.patch('logging.log') +@pytest.fixture +def mock_info_log(mocker): + logger = logging.getLogger('puppetboard.utils') + return mocker.patch.object(logger, 'info') + + +@pytest.fixture +def mock_err_log(mocker): + logger = logging.getLogger('puppetboard.utils') + return mocker.patch.object(logger, 'error') + + def test_http_error(mock_log): err = "NotFound" @@ -109,6 +121,73 @@ def test_http_empty(mock_log, mocker): flask_abort.assert_called_with('204') +def test_db_version_good(mocker, mock_info_log): + mocker.patch.object(app.puppetdb, 'current_version', return_value='4.2.0') + err = 'PuppetDB Version %d.%d.%d' % (4, 2, 0) + result = utils.get_db_version(app.puppetdb) + mock_info_log.assert_called_with(err) + assert (4, 0, 0) < result + assert (4, 2, 0) == result + assert (3, 2, 0) < result + assert (4, 3, 0) > result + assert (5, 0, 0) > result + assert (4, 2, 1) > result + + +def test_db_invalid_version(mocker, mock_err_log): + mocker.patch.object(app.puppetdb, 'current_version', return_value='4') + err = u"Unable to determine version from string: '%s'" % (4) + result = utils.get_db_version(app.puppetdb) + mock_err_log.assert_called_with(err) + assert (4, 0, 0) < result + assert (4, 2, 0) == result + + +def test_db_http_error(mocker, mock_err_log): + err = "NotFound" + + def raise_http_error(): + x = Response() + x.status_code = 404 + x.reason = err + raise HTTPError(err, response=x) + + mocker.patch.object(app.puppetdb, 'current_version', + side_effect=raise_http_error) + result = utils.get_db_version(app.puppetdb) + mock_err_log.assert_called_with(err) + assert result == () + + +def test_db_connection_error(mocker, mock_err_log): + err = "ConnectionError" + + def connection_error(): + x = Response() + x.status_code = 500 + x.reason = err + raise ConnectionError(err, response=x) + + mocker.patch.object(app.puppetdb, 'current_version', + side_effect=connection_error) + result = utils.get_db_version(app.puppetdb) + mock_err_log.assert_called_with(err) + assert result == () + + +def test_db_empty_response(mocker, mock_err_log): + err = "Empty Response" + + def connection_error(): + raise EmptyResponseError(err) + + mocker.patch.object(app.puppetdb, 'current_version', + side_effect=connection_error) + result = utils.get_db_version(app.puppetdb) + mock_err_log.assert_called_with(err) + assert result == () + + def test_iter(): test_list = (0, 1, 2, 3)