diff --git a/.coveragerc b/.coveragerc index 954413c..ad0247b 100644 --- a/.coveragerc +++ b/.coveragerc @@ -19,4 +19,4 @@ exclude_lines = raise NotImplementedError # Don't complain if non-runnable code isn't run: - if __name__ == .__main__.: + if __name__ == .__main__.: \ No newline at end of file diff --git a/src/grafana_api/dashboard.py b/src/grafana_api/dashboard.py index 2890d15..c33e364 100644 --- a/src/grafana_api/dashboard.py +++ b/src/grafana_api/dashboard.py @@ -56,7 +56,7 @@ def create_or_update_dashboard( else: logging.info("You successfully deployed the dashboard.") else: - logging.info( + logging.error( "There is no dashboard_path or dashboard_json or message defined." ) raise ValueError @@ -87,10 +87,10 @@ def delete_dashboard_by_name_and_path( else: logging.info("You successfully destroyed the dashboard.") else: - logging.info("Nothing to delete. There is no dashboard available.") + logging.error("Nothing to delete. There is no dashboard available.") raise ValueError else: - logging.info("There is no dashboard_name or dashboard_path defined.") + logging.error("There is no dashboard_name or dashboard_path defined.") raise ValueError def get_dashboard_by_uid(self, uid: str) -> dict: @@ -111,7 +111,7 @@ def get_dashboard_by_uid(self, uid: str) -> dict: else: return api_call else: - logging.info("There is no dashboard uid defined.") + logging.error("There is no dashboard uid defined.") raise ValueError def get_dashboard_home(self) -> dict: @@ -155,15 +155,32 @@ def get_dashboard_uid_and_id_by_name_and_folder( ).get_folder_id_by_dashboard_path(dashboard_path) search_query: str = f"{APIEndpoints.SEARCH.value}?folderIds={folder_id}&query={dashboard_name}" + print(search_query) dashboard_meta: list = Utils(self.grafana_api_model).call_the_api( search_query ) - return dict( - {"uid": dashboard_meta[0]["uid"], "id": dashboard_meta[0]["id"]} - ) + for dashboard_meta_object in dashboard_meta: + if dashboard_meta_object.get("title") is not None: + if dashboard_meta_object.get("title") == dashboard_name: + if ( + dashboard_meta_object.get("uid") is not None + and dashboard_meta_object.get("id") is not None + ): + return dict( + { + "uid": dashboard_meta_object.get("uid"), + "id": dashboard_meta_object.get("id"), + } + ) + else: + logging.error("There is no uid or id defined.") + raise ValueError + else: + logging.error("There is no title defined.") + raise ValueError else: - logging.info("There is no dashboard_name or dashboard_path defined.") + logging.error("There is no dashboard_name or dashboard_path defined.") raise ValueError def get_dashboard_permissions(self, id: int) -> list: @@ -184,7 +201,7 @@ def get_dashboard_permissions(self, id: int) -> list: else: return api_call else: - logging.info("There is no dashboard uid defined.") + logging.error("There is no dashboard uid defined.") raise ValueError def update_dashboard_permissions(self, id: int, permission_json: dict): @@ -209,7 +226,7 @@ def update_dashboard_permissions(self, id: int, permission_json: dict): else: logging.info("You successfully modified the dashboard permissions.") else: - logging.info("There is no dashboard uid or permission json defined.") + logging.error("There is no dashboard uid or permission json defined.") raise ValueError def get_dashboard_versions(self, id: int) -> list: @@ -230,7 +247,7 @@ def get_dashboard_versions(self, id: int) -> list: else: return api_call else: - logging.info("There is no dashboard uid defined.") + logging.error("There is no dashboard uid defined.") raise ValueError def get_dashboard_version(self, id: int, version_id: int) -> dict: @@ -253,7 +270,7 @@ def get_dashboard_version(self, id: int, version_id: int) -> dict: else: return api_call else: - logging.info("There is no dashboard uid or version_id defined.") + logging.error("There is no dashboard uid or version_id defined.") raise ValueError def restore_dashboard_version(self, id: int, version: dict): @@ -325,12 +342,12 @@ def calculate_dashboard_diff( else: return api_call.text else: - logging.info( + logging.error( "There is no dashboard_uid_and_version_base or dashboard_uid_and_version_new defined." ) raise ValueError else: - logging.info( + logging.error( f"The diff_type: {diff_type.lower()} is not valid. Please specify a valid value." ) raise ValueError diff --git a/src/grafana_api/folder.py b/src/grafana_api/folder.py index 904a264..b0682fb 100644 --- a/src/grafana_api/folder.py +++ b/src/grafana_api/folder.py @@ -46,7 +46,7 @@ def get_folder_by_uid(self, uid: str) -> dict: else: return api_call else: - logging.info("There is no dashboard uid defined.") + logging.error("There is no dashboard uid defined.") raise ValueError def get_folder_by_id(self, id: int) -> dict: @@ -67,7 +67,7 @@ def get_folder_by_id(self, id: int) -> dict: else: return api_call else: - logging.info("There is no folder id defined.") + logging.error("There is no folder id defined.") raise ValueError def create_folder(self, title: str, uid: str = None) -> dict: @@ -98,7 +98,7 @@ def create_folder(self, title: str, uid: str = None) -> dict: else: return api_call else: - logging.info("There is no folder uid or title defined.") + logging.error("There is no folder uid or title defined.") raise ValueError def update_folder( @@ -140,7 +140,7 @@ def update_folder( else: return api_call else: - logging.info("There is no folder title or version defined.") + logging.error("There is no folder title or version defined.") raise ValueError def delete_folder(self, uid: str): @@ -163,7 +163,7 @@ def delete_folder(self, uid: str): else: logging.info("You successfully destroyed the folder.") else: - logging.info("There is no folder uid defined.") + logging.error("There is no folder uid defined.") raise ValueError def get_folder_permissions(self, uid: str) -> list: @@ -186,7 +186,7 @@ def get_folder_permissions(self, uid: str) -> list: else: return api_call else: - logging.info("There is no folder uid defined.") + logging.error("There is no folder uid defined.") raise ValueError def update_folder_permissions(self, uid: str, permission_json: dict): @@ -211,12 +211,15 @@ def update_folder_permissions(self, uid: str, permission_json: dict): else: logging.info("You successfully modified the folder permissions.") else: - logging.info("There is no folder uid or permission json defined.") + logging.error("There is no folder uid or permission json defined.") raise ValueError def get_folder_id_by_dashboard_path(self, dashboard_path: str) -> int: """The method includes a functionality to extract the folder id specified inside model dashboard path""" + if dashboard_path.lower() == "general": + return 0 + if len(dashboard_path) != 0: folders: list = self.get_all_folder_ids_and_names() folder_id: int = 0 @@ -233,7 +236,7 @@ def get_folder_id_by_dashboard_path(self, dashboard_path: str) -> int: return folder_id else: - logging.info("There is no dashboard_path defined.") + logging.error("There is no dashboard_path defined.") raise ValueError def get_all_folder_ids_and_names(self) -> list: diff --git a/tests/integrationtest/resources/dashboard.json b/tests/integrationtest/resources/dashboard.json index f20876e..0925e53 100644 --- a/tests/integrationtest/resources/dashboard.json +++ b/tests/integrationtest/resources/dashboard.json @@ -1,30 +1,32 @@ { - "id": null, - "uid": "tests", - "title": "Test", - "tags": [], - "style": "dark", - "timezone": "browser", - "editable": true, - "hideControls": false, - "graphTooltip": 1, - "panels": [], - "time": { - "from": "now-6h", - "to": "now" - }, - "timepicker": { - "time_options": [], - "refresh_intervals": [] - }, - "templating": { - "list": [] - }, - "annotations": { - "list": [] - }, - "refresh": "5s", - "schemaVersion": 17, - "version": 0, - "links": [] + "dashboard": { + "id": null, + "uid": "tests", + "title": "Test", + "tags": [], + "style": "dark", + "timezone": "browser", + "editable": true, + "hideControls": false, + "graphTooltip": 1, + "panels": [], + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "time_options": [], + "refresh_intervals": [] + }, + "templating": { + "list": [] + }, + "annotations": { + "list": [] + }, + "refresh": "5s", + "schemaVersion": 17, + "version": 0, + "links": [] + } } \ No newline at end of file diff --git a/tests/integrationtest/resources/dashboard_expected_result.json b/tests/integrationtest/resources/dashboard_expected_result.json index 007becc..384914d 100644 --- a/tests/integrationtest/resources/dashboard_expected_result.json +++ b/tests/integrationtest/resources/dashboard_expected_result.json @@ -4,13 +4,13 @@ "list": [] }, "editable": true, - "graphTooltip": 1, - "hideControls": false, - "id": 104, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 152, "links": [], + "liveNow": false, "panels": [], - "refresh": "5s", - "schemaVersion": 17, + "schemaVersion": 34, "style": "dark", "tags": [], "templating": { @@ -20,36 +20,11 @@ "from": "now-6h", "to": "now" }, - "timepicker": { - "refresh_intervals": [], - "time_options": [] - }, - "timezone": "browser", + "timepicker": {}, + "timezone": "", "title": "Test 1", - "uid": "tests1", - "version": 1 - }, - "meta": { - "canAdmin": true, - "canEdit": true, - "canSave": true, - "canStar": true, - "created": "2022-01-15T20:46:44+01:00", - "createdBy": "Anonymous", - "expires": "0001-01-01T00:00:00Z", - "folderId": 72, - "folderTitle": "Github Integrationtest", - "folderUid": "6U_QdWJnz", - "folderUrl": "/dashboards/f/6U_QdWJnz/github-integrationtest", - "hasAcl": false, - "isFolder": false, - "provisioned": false, - "provisionedExternalId": "", - "slug": "test-1", - "type": "db", - "updated": "2022-01-15T20:46:44+01:00", - "updatedBy": "Anonymous", - "url": "/d/tests1/test-1", - "version": 1 + "uid": "test1", + "version": 3, + "weekStart": "" } } \ No newline at end of file diff --git a/tests/integrationtest/test_dashboard.py b/tests/integrationtest/test_dashboard.py index e59b991..392caff 100644 --- a/tests/integrationtest/test_dashboard.py +++ b/tests/integrationtest/test_dashboard.py @@ -25,18 +25,24 @@ def test_a_dashboard_creation(self): self.dashboard.create_or_update_dashboard( message="Create a new test dashboard", - dashboard_json=json_dashboard, + dashboard_json=json_dashboard.get("dashboard"), dashboard_path=os.environ["GRAFANA_DASHBOARD_PATH"], overwrite=True, ) self.assertEqual( - "tests", self.dashboard.get_dashboard_uid_and_id_by_name_and_folder( + "tests", + self.dashboard.get_dashboard_uid_and_id_by_name_and_folder( dashboard_path=os.environ["GRAFANA_DASHBOARD_PATH"], - dashboard_name=os.environ["GRAFANA_DASHBOARD_NAME"])["uid"] + dashboard_name=os.environ["GRAFANA_DASHBOARD_NAME"], + )["uid"], + ) + self.assertEqual( + 72, + self.folder.get_folder_id_by_dashboard_path( + dashboard_path=os.environ["GRAFANA_DASHBOARD_PATH"] + ), ) - self.assertEqual(72, self.folder.get_folder_id_by_dashboard_path( - dashboard_path=os.environ["GRAFANA_DASHBOARD_PATH"])) def test_b_get_dashboard(self): with open( @@ -44,18 +50,55 @@ def test_b_get_dashboard(self): ) as file: json_dashboard = json.load(file) - self.assertEqual(json_dashboard, self.dashboard.get_dashboard_by_uid("tests1")) + self.assertEqual( + json_dashboard.get("dashboard"), + self.dashboard.get_dashboard_by_uid("test1").get("dashboard"), + ) def test_c_dashboard_deletion(self): - self.dashboard.delete_dashboard_by_name_and_path(dashboard_path=os.environ["GRAFANA_DASHBOARD_PATH"], - dashboard_name=os.environ["GRAFANA_DASHBOARD_NAME"]) + self.dashboard.delete_dashboard_by_name_and_path( + dashboard_path=os.environ["GRAFANA_DASHBOARD_PATH"], + dashboard_name=os.environ["GRAFANA_DASHBOARD_NAME"], + ) + + def test_d_dashboard_creation_general_folder(self): + with open( + f"{os.getcwd()}{os.sep}tests{os.sep}integrationtest{os.sep}resources{os.sep}dashboard.json" + ) as file: + json_dashboard = json.load(file) + + self.dashboard.create_or_update_dashboard( + message="Create a new test dashboard", + dashboard_json=json_dashboard.get("dashboard"), + dashboard_path="General", + overwrite=True, + ) + + self.assertEqual( + "tests", + self.dashboard.get_dashboard_uid_and_id_by_name_and_folder( + dashboard_path="General", + dashboard_name=os.environ["GRAFANA_DASHBOARD_NAME"], + )["uid"], + ) + self.assertEqual( + 0, self.folder.get_folder_id_by_dashboard_path(dashboard_path="General") + ) + + def test_e_dashboard_deletion_general_folder(self): + self.dashboard.delete_dashboard_by_name_and_path( + dashboard_path="General", + dashboard_name=os.environ["GRAFANA_DASHBOARD_NAME"], + ) def test_wrong_token(self): self.model.token = "test" with self.assertRaises(requests.exceptions.ConnectionError): - self.dashboard.delete_dashboard_by_name_and_path(dashboard_path=os.environ["GRAFANA_DASHBOARD_PATH"], - dashboard_name=os.environ["GRAFANA_DASHBOARD_NAME"]) + self.dashboard.delete_dashboard_by_name_and_path( + dashboard_path=os.environ["GRAFANA_DASHBOARD_PATH"], + dashboard_name=os.environ["GRAFANA_DASHBOARD_NAME"], + ) if __name__ == "__main__": diff --git a/tests/unittests/test_dashboard.py b/tests/unittests/test_dashboard.py index a6731a3..4520ecf 100644 --- a/tests/unittests/test_dashboard.py +++ b/tests/unittests/test_dashboard.py @@ -100,6 +100,23 @@ def test_delete_dashboard_by_name_and_path_deletion_list_empty( dashboard_name="test", dashboard_path="test" ) + @patch("src.grafana_api.utils.Utils.call_the_api") + @patch( + "src.grafana_api.dashboard.Dashboard.get_dashboard_uid_and_id_by_name_and_folder" + ) + def test_delete_dashboard_by_name_and_path_dashboard_uid_id_is_none( + self, dashboard_uid_and_id_by_name_and_folder_mock, call_the_api_mock + ): + model: APIModel = APIModel(host=MagicMock(), token=MagicMock()) + dashboard: Dashboard = Dashboard(grafana_api_model=model) + + dashboard_uid_and_id_by_name_and_folder_mock.return_value = None + call_the_api_mock.return_value = dict({"message": "error"}) + with self.assertRaises(TypeError): + dashboard.delete_dashboard_by_name_and_path( + dashboard_name="test", dashboard_path="test" + ) + @patch("src.grafana_api.utils.Utils.call_the_api") @patch( "src.grafana_api.dashboard.Dashboard.get_dashboard_uid_and_id_by_name_and_folder" @@ -128,7 +145,7 @@ def test_get_dashboard_uid_and_id_by_name_and_folder( dashboard: Dashboard = Dashboard(grafana_api_model=model) folder_id_by_dashboard_path_mock.return_value = 1 - call_the_api_mock.return_value = [{"uid": "test", "id": 10}] + call_the_api_mock.return_value = [{"uid": "test", "id": 10, "title": "test"}] self.assertEqual( dict({"uid": "test", "id": 10}), dashboard.get_dashboard_uid_and_id_by_name_and_folder( @@ -136,7 +153,71 @@ def test_get_dashboard_uid_and_id_by_name_and_folder( ), ) - def test_get_dashboard_uid_and_id_by_name_and_folder_bo_dashboard_name_defined( + @patch("src.grafana_api.utils.Utils.call_the_api") + @patch("src.grafana_api.folder.Folder.get_folder_id_by_dashboard_path") + def test_get_dashboard_uid_and_id_by_name_and_folder_no_id_inside_dashboard_meta_object( + self, folder_id_by_dashboard_path_mock, call_the_api_mock + ): + model: APIModel = APIModel(host=MagicMock(), token=MagicMock()) + dashboard: Dashboard = Dashboard(grafana_api_model=model) + + folder_id_by_dashboard_path_mock.return_value = 1 + call_the_api_mock.return_value = [{"uid": "test", "title": "test"}] + with self.assertRaises(ValueError): + dashboard.get_dashboard_uid_and_id_by_name_and_folder( + dashboard_name="test", dashboard_path="test" + ) + + @patch("src.grafana_api.utils.Utils.call_the_api") + @patch("src.grafana_api.folder.Folder.get_folder_id_by_dashboard_path") + def test_get_dashboard_uid_and_id_by_name_and_folder_no_title_inside_dashboard_meta_object( + self, folder_id_by_dashboard_path_mock, call_the_api_mock + ): + model: APIModel = APIModel(host=MagicMock(), token=MagicMock()) + dashboard: Dashboard = Dashboard(grafana_api_model=model) + + folder_id_by_dashboard_path_mock.return_value = 1 + call_the_api_mock.return_value = [{"uid": "test", "id": 1}] + with self.assertRaises(ValueError): + dashboard.get_dashboard_uid_and_id_by_name_and_folder( + dashboard_name="test", dashboard_path="test" + ) + + @patch("src.grafana_api.utils.Utils.call_the_api") + @patch("src.grafana_api.folder.Folder.get_folder_id_by_dashboard_path") + def test_get_dashboard_uid_and_id_by_name_and_folder_no_matched_title_inside_dashboard_meta_object( + self, folder_id_by_dashboard_path_mock, call_the_api_mock + ): + model: APIModel = APIModel(host=MagicMock(), token=MagicMock()) + dashboard: Dashboard = Dashboard(grafana_api_model=model) + + folder_id_by_dashboard_path_mock.return_value = 1 + call_the_api_mock.return_value = [{"uid": "test", "title": "test123", "id": 1}] + self.assertEqual( + None, + dashboard.get_dashboard_uid_and_id_by_name_and_folder( + dashboard_name="test", dashboard_path="test" + ), + ) + + @patch("src.grafana_api.utils.Utils.call_the_api") + @patch("src.grafana_api.folder.Folder.get_folder_id_by_dashboard_path") + def test_get_dashboard_uid_and_id_by_name_and_folder_empty_result( + self, folder_id_by_dashboard_path_mock, call_the_api_mock + ): + model: APIModel = APIModel(host=MagicMock(), token=MagicMock()) + dashboard: Dashboard = Dashboard(grafana_api_model=model) + + folder_id_by_dashboard_path_mock.return_value = 1 + call_the_api_mock.return_value = [] + self.assertEqual( + None, + dashboard.get_dashboard_uid_and_id_by_name_and_folder( + dashboard_name="test", dashboard_path="test" + ), + ) + + def test_get_dashboard_uid_and_id_by_name_and_folder_no_dashboard_name_defined( self, ): model: APIModel = APIModel(host=MagicMock(), token=MagicMock()) diff --git a/tests/unittests/test_folder.py b/tests/unittests/test_folder.py index 9f5efa5..eae9275 100644 --- a/tests/unittests/test_folder.py +++ b/tests/unittests/test_folder.py @@ -83,9 +83,7 @@ def test_create_folder(self, call_the_api_mock): folder: Folder = Folder(grafana_api_model=model) call_the_api_mock.return_value = dict({"title": None, "id": 12}) - self.assertEqual( - dict({"title": None, "id": 12}), folder.create_folder("test") - ) + self.assertEqual(dict({"title": None, "id": 12}), folder.create_folder("test")) @patch("src.grafana_api.utils.Utils.call_the_api") def test_create_folder_specified_uid(self, call_the_api_mock): @@ -94,7 +92,8 @@ def test_create_folder_specified_uid(self, call_the_api_mock): call_the_api_mock.return_value = dict({"title": None, "id": 12, "uid": "test"}) self.assertEqual( - dict({"title": None, "id": 12, "uid": "test"}), folder.create_folder("test", "test") + dict({"title": None, "id": 12, "uid": "test"}), + folder.create_folder("test", "test"), ) @patch("src.grafana_api.utils.Utils.call_the_api") @@ -122,7 +121,8 @@ def test_update_folder(self, call_the_api_mock): call_the_api_mock.return_value = dict({"title": "test1", "id": 12}) self.assertEqual( - dict({"title": "test1", "id": 12}), folder.update_folder("test", "test1", 10) + dict({"title": "test1", "id": 12}), + folder.update_folder("test", "test1", 10), ) @patch("src.grafana_api.utils.Utils.call_the_api") @@ -255,6 +255,14 @@ def test_get_folder_id_by_dashboard_path(self, all_folder_ids_and_names_mock): 12, folder.get_folder_id_by_dashboard_path(dashboard_path="test") ) + def test_get_folder_id_by_dashboard_path_general_path(self): + model: APIModel = APIModel(host=MagicMock(), token=MagicMock()) + folder: Folder = Folder(grafana_api_model=model) + + self.assertEqual( + 0, folder.get_folder_id_by_dashboard_path(dashboard_path="General") + ) + def test_get_folder_id_by_dashboard_path_no_dashboard_path_defined(self): model: APIModel = APIModel(host=MagicMock(), token=MagicMock()) folder: Folder = Folder(grafana_api_model=model)