3
3
import re
4
4
from io import StringIO
5
5
from pathlib import Path
6
+ from typing import List , Union
6
7
7
8
import grafanalib .core
8
9
import pytest
12
13
from grafana_wtf .core import GrafanaWtf
13
14
14
15
# Whether to clean up all resources provisioned to Grafana.
16
+ # Note that the test suite will not complete successfully when toggling this
17
+ # setting. It can be used when running individual test cases in order to
18
+ # investigate the resources provisioned to Grafana.
15
19
CLEANUP_RESOURCES = True
16
20
17
21
@@ -56,6 +60,38 @@ def create_datasource(docker_grafana):
56
60
57
61
- https://grafana.com/docs/grafana/latest/http_api/data_source/
58
62
- https://docs.pytest.org/en/4.6.x/fixture.html#factories-as-fixtures
63
+
64
+ The JSON response to `create_datasource` looks like this::
65
+
66
+ {
67
+ "datasource": {
68
+ "id": 3,
69
+ "uid": "PDF2762CDFF14A314",
70
+ "orgId": 1,
71
+ "name": "ldi_v2",
72
+ "type": "influxdb",
73
+ "typeLogoUrl": "",
74
+ "access": "proxy",
75
+ "url": "http://localhost:8086/",
76
+ "password": "root",
77
+ "user": "root",
78
+ "database": "ldi_v2",
79
+ "basicAuth": false,
80
+ "basicAuthUser": "",
81
+ "basicAuthPassword": "",
82
+ "withCredentials": false,
83
+ "isDefault": false,
84
+ "jsonData": {},
85
+ "secureJsonFields": {
86
+ "password": true
87
+ },
88
+ "version": 1,
89
+ "readOnly": false
90
+ },
91
+ "id": 3,
92
+ "message": "Datasource added",
93
+ "name": "ldi_v2"
94
+ }
59
95
"""
60
96
61
97
# Reference to `grafana-client`.
@@ -64,7 +100,19 @@ def create_datasource(docker_grafana):
64
100
# Keep track of the datasource ids in order to delete them afterwards.
65
101
datasource_ids = []
66
102
67
- def _create_datasource (name : str , type : str , access : str , ** kwargs ):
103
+ def _create_datasource (name : str , type : str = "testdata" , access : str = "proxy" , ** kwargs ):
104
+
105
+ # Reuse existing datasource.
106
+ try :
107
+ response = grafana .datasource .get_datasource_by_name (name )
108
+ datasource_id = response ["id" ]
109
+ datasource_ids .append (datasource_id )
110
+ return
111
+ except GrafanaClientError as ex :
112
+ if ex .status_code != 404 :
113
+ raise
114
+
115
+ # Create new datasource.
68
116
datasource = dict (name = name , type = type , access = access )
69
117
datasource .update (kwargs )
70
118
try :
@@ -91,60 +139,74 @@ def _create_datasource(name: str, type: str, access: str, **kwargs):
91
139
def create_folder (docker_grafana ):
92
140
"""
93
141
Create a Grafana folder from a test case.
94
- After the test case finished, it will remove the dashboard again.
142
+ After the test case finished, it will remove the folder again.
95
143
96
144
- https://grafana.com/docs/grafana/latest/http_api/folder/
97
145
- https://docs.pytest.org/en/4.6.x/fixture.html#factories-as-fixtures
146
+
147
+ The JSON response to `create_folder` looks like this::
148
+
149
+ {
150
+ "id": 44,
151
+ "uid": "iga1UrEnz",
152
+ "title": "Testdrive",
153
+ "url": "/dashboards/f/iga1UrEnz/testdrive",
154
+ "hasAcl": false,
155
+ "canSave": true,
156
+ "canEdit": true,
157
+ "canAdmin": true,
158
+ "createdBy": "admin",
159
+ "created": "2022-03-22T23:44:38Z",
160
+ "updatedBy": "admin",
161
+ "updated": "2022-03-22T23:44:38Z",
162
+ "version": 1
163
+ }
98
164
"""
99
165
100
166
# Reference to `grafana-client`.
101
167
grafana = GrafanaWtf .grafana_client_factory (docker_grafana )
102
168
103
- # Keep track of the dashboard uids in order to delete them afterwards.
169
+ # Keep track of the folder uids in order to delete them afterwards.
104
170
folder_uids = []
105
171
106
- # https://docs.pytest.org/en/4.6.x/fixture.html#factories-as-fixtures
107
172
def _create_folder (title : str , uid : str = None ):
108
173
109
- # Create dashboard in Grafana .
174
+ # Reuse folder when it already exists .
110
175
try :
111
- response = grafana .folder .create_folder ( title = title , uid = uid )
176
+ response = grafana .folder .get_folder ( uid = uid )
112
177
folder_id = response ["id" ]
113
178
folder_uid = response ["uid" ]
179
+ folder_uids .append (folder_uid )
180
+ return folder_id
181
+ except GrafanaClientError as ex :
182
+ if ex .status_code != 404 :
183
+ raise
114
184
115
- # Response is like:
116
- """
117
- {
118
- "id": 44,
119
- "uid": "iga1UrEnz",
120
- "title": "Testdrive",
121
- "url": "/dashboards/f/iga1UrEnz/testdrive",
122
- "hasAcl": false,
123
- "canSave": true,
124
- "canEdit": true,
125
- "canAdmin": true,
126
- "createdBy": "admin",
127
- "created": "2022-03-22T23:44:38Z",
128
- "updatedBy": "admin",
129
- "updated": "2022-03-22T23:44:38Z",
130
- "version": 1
131
- }
132
- """
133
-
185
+ # Create folder.
186
+ try :
187
+ response = grafana .folder .create_folder (title = title , uid = uid )
188
+ folder_id = response ["id" ]
189
+ folder_uid = response ["uid" ]
134
190
folder_uids .append (folder_uid )
135
191
return folder_id
136
192
except GrafanaClientError as ex :
137
193
# TODO: Mimic the original response in order to make the removal work.
138
- if not re .match (
194
+ error_exists = re .match (
139
195
"Client Error 409: a folder or dashboard in the general folder with the same name already exists" ,
140
196
str (ex ),
141
197
re .IGNORECASE ,
142
- ):
198
+ )
199
+ error_modified = re .match (
200
+ "Client Error 412: The folder has been changed by someone else" ,
201
+ str (ex ),
202
+ re .IGNORECASE ,
203
+ )
204
+ if not (error_exists or error_modified ):
143
205
raise
144
206
145
207
yield _create_folder
146
208
147
- # Delete dashboard again.
209
+ # Delete folder again.
148
210
if CLEANUP_RESOURCES :
149
211
if folder_uids :
150
212
for folder_uid in folder_uids :
@@ -159,6 +221,17 @@ def create_dashboard(docker_grafana):
159
221
160
222
- https://grafana.com/docs/grafana/latest/http_api/dashboard/
161
223
- https://docs.pytest.org/en/4.6.x/fixture.html#factories-as-fixtures
224
+
225
+ The JSON response to `update_dashboard` looks like this::
226
+
227
+ {
228
+ "id": 2,
229
+ "slug": "luftdaten-info-generic-trend-v33",
230
+ "status": "success",
231
+ "uid": "jpVsQxRja",
232
+ "url": "/d/jpVsQxRja/luftdaten-info-generic-trend-v33",
233
+ "version": 1
234
+ }
162
235
"""
163
236
164
237
# Reference to `grafana-client`.
@@ -177,10 +250,6 @@ def _create_dashboard(dashboard: dict = None, folder_id: str = None, folder_uid:
177
250
if folder_uid :
178
251
payload ["folderUid" ] = folder_uid
179
252
response = grafana .dashboard .update_dashboard (dashboard = payload )
180
-
181
- # Response is like:
182
- # {'id': 3, 'slug': 'foo', 'status': 'success', 'uid': 'iO0xgE2nk', 'url': '/d/iO0xgE2nk/foo', 'version': 1}
183
-
184
253
dashboard_uid = response ["uid" ]
185
254
dashboard_uids .append (dashboard_uid )
186
255
@@ -202,26 +271,46 @@ def ldi_resources(create_datasource, create_folder, create_dashboard):
202
271
https://docs.pytest.org/en/4.6.x/fixture.html#factories-as-fixtures
203
272
"""
204
273
205
- # Create LDI datasource.
206
- create_datasource (
207
- name = "ldi_v2" ,
208
- type = "influxdb" ,
209
- access = "proxy" ,
210
- url = "http://localhost:8086/" ,
211
- user = "root" ,
212
- password = "root" ,
213
- database = "ldi_v2" ,
214
- secureJsonData = {"password" : "root" },
215
- )
216
-
217
- # Create folder.
218
- folder_id = create_folder (title = "Testdrive" , uid = "testdrive" )
219
-
220
- # Create LDI dashboards.
221
- for file in Path ("tests/grafana/dashboards" ).glob ("*.json" ):
222
- with open (file , "r" ) as f :
223
- dashboard = json .load (f )
224
- create_dashboard (dashboard = dashboard , folder_id = folder_id )
274
+ def _ldi_resources (dashboards : List [Union [Path , str ]] = None ):
275
+ # Create LDI datasource.
276
+ create_datasource (
277
+ name = "ldi_v2" ,
278
+ type = "influxdb" ,
279
+ access = "proxy" ,
280
+ uid = "PDF2762CDFF14A314" ,
281
+ url = "http://localhost:8086/" ,
282
+ user = "root" ,
283
+ password = "root" ,
284
+ database = "ldi_v2" ,
285
+ secureJsonData = {"password" : "root" },
286
+ )
287
+
288
+ # Create folder.
289
+ folder_id = create_folder (title = "Testdrive" , uid = "testdrive" )
290
+
291
+ # Create LDI dashboards.
292
+ if dashboards :
293
+ dashboard_files = dashboards
294
+ else :
295
+ dashboard_files = Path ("tests/grafana/dashboards" ).glob ("*.json" )
296
+
297
+ for file in dashboard_files :
298
+ with open (file , "r" ) as f :
299
+ dashboard = json .load (f )
300
+ create_dashboard (dashboard = dashboard , folder_id = folder_id )
301
+
302
+ return _ldi_resources
303
+
304
+
305
+ @pytest .fixture
306
+ def grafana_version (docker_grafana ):
307
+ """
308
+ Return Grafana version number.
309
+ """
310
+ engine = GrafanaWtf (grafana_url = docker_grafana , grafana_token = None )
311
+ engine .setup ()
312
+ grafana_version = engine .version ()
313
+ return grafana_version
225
314
226
315
227
316
def mkdashboard (title : str , datasource : str ):
0 commit comments