robotframework-robotlog2rqm 1.2.1__py3-none-any.whl → 1.2.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- RobotLog2RQM/CRQM.py +114 -111
- RobotLog2RQM/RobotLog2RQM.pdf +0 -0
- RobotLog2RQM/__init__.py +1 -1
- RobotLog2RQM/__main__.py +2 -2
- RobotLog2RQM/robotlog2rqm.py +37 -36
- RobotLog2RQM/version.py +3 -3
- {robotframework_robotlog2rqm-1.2.1.dist-info → robotframework_robotlog2rqm-1.2.4.dist-info}/METADATA +12 -12
- robotframework_robotlog2rqm-1.2.4.dist-info/RECORD +19 -0
- {robotframework_robotlog2rqm-1.2.1.dist-info → robotframework_robotlog2rqm-1.2.4.dist-info}/WHEEL +1 -1
- robotframework_robotlog2rqm-1.2.1.dist-info/RECORD +0 -19
- {robotframework_robotlog2rqm-1.2.1.dist-info → robotframework_robotlog2rqm-1.2.4.dist-info}/LICENSE +0 -0
- {robotframework_robotlog2rqm-1.2.1.dist-info → robotframework_robotlog2rqm-1.2.4.dist-info}/entry_points.txt +0 -0
- {robotframework_robotlog2rqm-1.2.1.dist-info → robotframework_robotlog2rqm-1.2.4.dist-info}/top_level.txt +0 -0
RobotLog2RQM/CRQM.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2020-
|
|
1
|
+
# Copyright 2020-2023 Robert Bosch GmbH
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
# Initialy created by Tran Duy Ngoan(RBVH/ECM11) / January 2021
|
|
19
19
|
#
|
|
20
20
|
# This is CRQMClient class which is used to interact with RQM via RQM REST APIs
|
|
21
|
-
#
|
|
21
|
+
#
|
|
22
22
|
# History:
|
|
23
|
-
#
|
|
23
|
+
#
|
|
24
24
|
# 2020-01-08:
|
|
25
25
|
# - initial version
|
|
26
26
|
#
|
|
@@ -41,7 +41,7 @@ requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
|
|
41
41
|
#
|
|
42
42
|
# helper functions for processing xml data
|
|
43
43
|
#
|
|
44
|
-
########################################################################
|
|
44
|
+
########################################################################
|
|
45
45
|
|
|
46
46
|
def get_xml_tree(file_name, bdtd_validation=True):
|
|
47
47
|
"""
|
|
@@ -81,7 +81,7 @@ Parse xml object from file.
|
|
|
81
81
|
#
|
|
82
82
|
# IBM Rational Quality Manager
|
|
83
83
|
#
|
|
84
|
-
###########################################################################
|
|
84
|
+
###########################################################################
|
|
85
85
|
class CRQMClient():
|
|
86
86
|
"""
|
|
87
87
|
CRQMClient class uses RQM REST APIs to get, create and update resources
|
|
@@ -99,13 +99,13 @@ Resoure type mapping:
|
|
|
99
99
|
* executionworkitem: Test Execution Record (TCER)
|
|
100
100
|
* executionresult: Execution Result
|
|
101
101
|
"""
|
|
102
|
-
RESULT_STATES = ['paused', 'inprogress', 'notrun', 'passed', 'incomplete',
|
|
103
|
-
'inconclusive', 'part_blocked', 'failed', 'error',
|
|
102
|
+
RESULT_STATES = ['paused', 'inprogress', 'notrun', 'passed', 'incomplete',
|
|
103
|
+
'inconclusive', 'part_blocked', 'failed', 'error',
|
|
104
104
|
'blocked', 'perm_failed', 'deferred']
|
|
105
105
|
|
|
106
106
|
# This namespace definition is used when update resource because the namespace
|
|
107
107
|
# definition is response(get from ETM) maybe different with the using template.
|
|
108
|
-
# There is a deviation in namespace definition between IBM Rational Quality
|
|
108
|
+
# There is a deviation in namespace definition between IBM Rational Quality
|
|
109
109
|
# Manager(RQM) v6 and IBM Engineering Test Management (ETM) v7.
|
|
110
110
|
# (from ns1->ns7, only change values within ns order, no new definition).
|
|
111
111
|
NAMESPACES = {
|
|
@@ -146,27 +146,27 @@ Constructor of class ``CRQMClient``.
|
|
|
146
146
|
/ *Condition*: required / *Type*: str /
|
|
147
147
|
|
|
148
148
|
User password for RQM's authentication.
|
|
149
|
-
|
|
149
|
+
|
|
150
150
|
* ``project``
|
|
151
151
|
|
|
152
152
|
/ *Condition*: required / *Type*: str /
|
|
153
153
|
|
|
154
154
|
The RQM project name.
|
|
155
|
-
|
|
155
|
+
|
|
156
156
|
* ``host``
|
|
157
157
|
|
|
158
158
|
/ *Condition*: required / *Type*: str /
|
|
159
159
|
|
|
160
160
|
The url that RQM is hosted.
|
|
161
161
|
"""
|
|
162
|
-
# RQM authentication
|
|
162
|
+
# RQM authentication
|
|
163
163
|
self.host = host
|
|
164
164
|
self.userID = user
|
|
165
165
|
self.pw = password
|
|
166
166
|
self.projectname = project
|
|
167
167
|
self.projectID = urllib.parse.quote_plus(project) # encode URI for project name
|
|
168
168
|
self.session = requests.Session()
|
|
169
|
-
|
|
169
|
+
self.session.auth = (self.userID, self.pw)
|
|
170
170
|
# Required request headers for creating new resource
|
|
171
171
|
self.headers = {
|
|
172
172
|
'Accept' : 'application/xml',
|
|
@@ -214,12 +214,15 @@ Log in RQM by provided user & password.
|
|
|
214
214
|
Indicates if the computation of the method ``login`` was successful or not.
|
|
215
215
|
"""
|
|
216
216
|
bSuccess = False
|
|
217
|
-
|
|
217
|
+
# from requests_kerberos import HTTPKerberosAuth, OPTIONAL
|
|
218
|
+
# kerberos_auth = HTTPKerberosAuth(mutual_authentication=OPTIONAL)
|
|
219
|
+
# self.session.auth = (self.userID, self.pw)
|
|
220
|
+
res = self.session.post(self.host + '/qm/j_security_check', allow_redirects=True, verify=False,
|
|
218
221
|
data={'j_username':self.userID,'j_password':self.pw})
|
|
219
222
|
if res.status_code == 200:
|
|
220
223
|
# verify login
|
|
221
224
|
if self.verifyProjectName():
|
|
222
|
-
# When the authentication is successful, the JSESSIONID from cookies will
|
|
225
|
+
# When the authentication is successful, the JSESSIONID from cookies will
|
|
223
226
|
# be stored as header for later POST method.
|
|
224
227
|
try:
|
|
225
228
|
self.headers['X-Jazz-CSRF-Prevent'] = self.session.cookies['JSESSIONID']
|
|
@@ -229,7 +232,7 @@ Log in RQM by provided user & password.
|
|
|
229
232
|
return bSuccess
|
|
230
233
|
|
|
231
234
|
def verifyProjectName(self):
|
|
232
|
-
"""
|
|
235
|
+
"""
|
|
233
236
|
Verify the project name by searching it in `project-areas` XML response.
|
|
234
237
|
|
|
235
238
|
**Arguments:**
|
|
@@ -249,7 +252,7 @@ Verify the project name by searching it in `project-areas` XML response.
|
|
|
249
252
|
# The found project ID will be stored and:
|
|
250
253
|
# - required for `team-areas` request (project name cannot be used)
|
|
251
254
|
# - used for all later request urls instead of project name
|
|
252
|
-
resProjects = self.session.get(self.host + '/qm/process/project-areas',
|
|
255
|
+
resProjects = self.session.get(self.host + '/qm/process/project-areas',
|
|
253
256
|
allow_redirects=True, verify=False)
|
|
254
257
|
if resProjects.status_code == 200:
|
|
255
258
|
oProjects=get_xml_tree(BytesIO(str(resProjects.text).encode()),
|
|
@@ -265,7 +268,7 @@ Verify the project name by searching it in `project-areas` XML response.
|
|
|
265
268
|
if not bSuccess:
|
|
266
269
|
raise Exception(f"Could not find project with name '{self.projectname}'")
|
|
267
270
|
|
|
268
|
-
return bSuccess
|
|
271
|
+
return bSuccess
|
|
269
272
|
|
|
270
273
|
def disconnect(self):
|
|
271
274
|
"""
|
|
@@ -281,7 +284,7 @@ Disconnect from RQM.
|
|
|
281
284
|
"""
|
|
282
285
|
self.session.close()
|
|
283
286
|
|
|
284
|
-
def config(self, plan_id, build_name=None, config_name=None,
|
|
287
|
+
def config(self, plan_id, build_name=None, config_name=None,
|
|
285
288
|
createmissing=False, updatetestcase=False,suite_id=None):
|
|
286
289
|
"""
|
|
287
290
|
Configure RQMClient with testplan ID, build, configuration, createmissing, ...
|
|
@@ -300,7 +303,7 @@ Configure RQMClient with testplan ID, build, configuration, createmissing, ...
|
|
|
300
303
|
|
|
301
304
|
* ``build_name``
|
|
302
305
|
|
|
303
|
-
/ *Condition*: optional / *Type*: str / *Default*: None /
|
|
306
|
+
/ *Condition*: optional / *Type*: str / *Default*: None /
|
|
304
307
|
|
|
305
308
|
The `Build Record` for linking result(s).
|
|
306
309
|
Set it to `None` if not be used, the empty name '' will lead to error.
|
|
@@ -315,13 +318,13 @@ Configure RQMClient with testplan ID, build, configuration, createmissing, ...
|
|
|
315
318
|
* ``createmissing``
|
|
316
319
|
|
|
317
320
|
/ *Condition*: optional / *Type*: bool / *Default*: False /
|
|
318
|
-
|
|
321
|
+
|
|
319
322
|
If `True`, the testcase without `tcid` information will be created on RQM.
|
|
320
323
|
|
|
321
324
|
* ``updatetestcase``
|
|
322
325
|
|
|
323
326
|
/ *Condition*: optional / *Type*: bool / *Default*: False /
|
|
324
|
-
|
|
327
|
+
|
|
325
328
|
If `True`, the information of testcase on RQM will be updated bases on robot testfile.
|
|
326
329
|
|
|
327
330
|
* ``suite_id (optional)``
|
|
@@ -391,7 +394,7 @@ Return interaction URL of provided userID
|
|
|
391
394
|
* ``userURL``
|
|
392
395
|
|
|
393
396
|
/ *Type*: str /
|
|
394
|
-
|
|
397
|
+
|
|
395
398
|
The interaction URL of provided userID.
|
|
396
399
|
"""
|
|
397
400
|
userURL = self.host + "/jts/resource/itemName/com.ibm.team.repository.Contributor/" + userID
|
|
@@ -419,7 +422,7 @@ The provided ID can be internalID (contains only digits) or externalID.
|
|
|
419
422
|
* If given: the specified url to resource ID is returned.
|
|
420
423
|
* If ``None``: the url to resource type (to get all entity) is returned.
|
|
421
424
|
|
|
422
|
-
* ``forceinternalID``
|
|
425
|
+
* ``forceinternalID``
|
|
423
426
|
|
|
424
427
|
/ *Condition*: optional / *Type*: bool / *Default*: False /
|
|
425
428
|
|
|
@@ -434,14 +437,14 @@ The provided ID can be internalID (contains only digits) or externalID.
|
|
|
434
437
|
The interaction URL of provided reource and ID.
|
|
435
438
|
"""
|
|
436
439
|
integrationURL = self.host + "/qm/service/com.ibm.rqm.integration.service.IIntegrationService/resources/" + \
|
|
437
|
-
self.projectID + '/' + resourceType
|
|
440
|
+
self.projectID + '/' + resourceType
|
|
438
441
|
if(id != None):
|
|
439
442
|
### externalID
|
|
440
443
|
if (not str(id).isdigit()) and (not forceinternalID):
|
|
441
|
-
integrationURL += '/'+ str(id)
|
|
444
|
+
integrationURL += '/'+ str(id)
|
|
442
445
|
else:
|
|
443
446
|
### internalID
|
|
444
|
-
integrationURL += "/urn:com.ibm.rqm:" + resourceType + ':' + str(id)
|
|
447
|
+
integrationURL += "/urn:com.ibm.rqm:" + resourceType + ':' + str(id)
|
|
445
448
|
return integrationURL
|
|
446
449
|
|
|
447
450
|
def webIDfromResponse(self, response, tagID='rqm:resultId'):
|
|
@@ -470,7 +473,7 @@ Note:
|
|
|
470
473
|
* ``resultId``
|
|
471
474
|
|
|
472
475
|
/ *Type*: str /
|
|
473
|
-
|
|
476
|
+
|
|
474
477
|
The internal ID (as number).
|
|
475
478
|
"""
|
|
476
479
|
resultId = ''
|
|
@@ -511,22 +514,22 @@ Note:
|
|
|
511
514
|
* ``webID``
|
|
512
515
|
|
|
513
516
|
/ *Type*: str /
|
|
514
|
-
|
|
517
|
+
|
|
515
518
|
The web ID (as number).
|
|
516
519
|
"""
|
|
517
520
|
webID = generateID
|
|
518
521
|
# below resources that have ns2:webId node in response data
|
|
519
|
-
lSupportedResources = [ 'attachment',
|
|
520
|
-
'executionresult',
|
|
521
|
-
'executionscript',
|
|
522
|
-
'executionworkitem',
|
|
523
|
-
'keyword',
|
|
524
|
-
'remotescript',
|
|
525
|
-
'suiteexecutionrecord',
|
|
526
|
-
'testcase',
|
|
527
|
-
'testplan',
|
|
528
|
-
'testscript',
|
|
529
|
-
'testsuite',
|
|
522
|
+
lSupportedResources = [ 'attachment',
|
|
523
|
+
'executionresult',
|
|
524
|
+
'executionscript',
|
|
525
|
+
'executionworkitem',
|
|
526
|
+
'keyword',
|
|
527
|
+
'remotescript',
|
|
528
|
+
'suiteexecutionrecord',
|
|
529
|
+
'testcase',
|
|
530
|
+
'testplan',
|
|
531
|
+
'testscript',
|
|
532
|
+
'testsuite',
|
|
530
533
|
'testsuitelog']
|
|
531
534
|
if resourrceType in lSupportedResources:
|
|
532
535
|
resResource = self.getResourceByID(resourrceType, generateID)
|
|
@@ -558,7 +561,7 @@ Return data of provided resource and ID by GET method
|
|
|
558
561
|
|
|
559
562
|
* ``id``
|
|
560
563
|
|
|
561
|
-
/ *Condition*: required / *Type*: str /
|
|
564
|
+
/ *Condition*: required / *Type*: str /
|
|
562
565
|
|
|
563
566
|
ID of resource.
|
|
564
567
|
|
|
@@ -570,7 +573,7 @@ Return data of provided resource and ID by GET method
|
|
|
570
573
|
|
|
571
574
|
Response data of GET request.
|
|
572
575
|
"""
|
|
573
|
-
res = self.session.get(self.integrationURL(resourceType, id),
|
|
576
|
+
res = self.session.get(self.integrationURL(resourceType, id),
|
|
574
577
|
allow_redirects=True, verify=False)
|
|
575
578
|
return res
|
|
576
579
|
|
|
@@ -599,14 +602,14 @@ Return all entries (in all pages) of provided resource by GET method.
|
|
|
599
602
|
.. code:: python
|
|
600
603
|
|
|
601
604
|
{
|
|
602
|
-
'success' : False,
|
|
605
|
+
'success' : False,
|
|
603
606
|
'message' : '',
|
|
604
607
|
'data' : {}
|
|
605
608
|
}
|
|
606
609
|
|
|
607
610
|
"""
|
|
608
611
|
dReturn = {
|
|
609
|
-
'success' : False,
|
|
612
|
+
'success' : False,
|
|
610
613
|
'message' : '',
|
|
611
614
|
'data' : {}
|
|
612
615
|
}
|
|
@@ -622,7 +625,7 @@ Return all entries (in all pages) of provided resource by GET method.
|
|
|
622
625
|
sEntryID = (sURLID.split("/")[-1]).split(":")[-1]
|
|
623
626
|
sEntryName = oEntry.find("./title", nsmap).text
|
|
624
627
|
dReturn['data'][sEntryID] = sEntryName
|
|
625
|
-
|
|
628
|
+
|
|
626
629
|
# Try to get data from next page
|
|
627
630
|
oNextPage = oResData.find('./link[@rel="next"]', nsmap)
|
|
628
631
|
if oNextPage != None:
|
|
@@ -679,7 +682,7 @@ Get all available configurations of project on RQM and store them into `dConfigu
|
|
|
679
682
|
"""
|
|
680
683
|
Get all available team-areas of project on RQM and store them into `dTeamAreas` property.
|
|
681
684
|
|
|
682
|
-
Example:
|
|
685
|
+
Example:
|
|
683
686
|
|
|
684
687
|
.. code:: python
|
|
685
688
|
|
|
@@ -708,7 +711,7 @@ Example:
|
|
|
708
711
|
self.dTeamAreas[sTeamName] = sTeamURL
|
|
709
712
|
else:
|
|
710
713
|
raise Exception(f"Could not get 'team-areas' of project '{self.projectname}'.")
|
|
711
|
-
|
|
714
|
+
|
|
712
715
|
|
|
713
716
|
#
|
|
714
717
|
# Methods to create XML template for resources
|
|
@@ -718,7 +721,7 @@ Example:
|
|
|
718
721
|
"""
|
|
719
722
|
Append `team-area` node which contains URL to given team-area into xml template.
|
|
720
723
|
|
|
721
|
-
Note:
|
|
724
|
+
Note:
|
|
722
725
|
`team-area` information is case-casesensitive
|
|
723
726
|
|
|
724
727
|
**Arguments:**
|
|
@@ -754,8 +757,8 @@ Note:
|
|
|
754
757
|
|
|
755
758
|
return root
|
|
756
759
|
|
|
757
|
-
def createTestcaseTemplate(self, testcaseName, sDescription='',
|
|
758
|
-
sComponent='', sFID='', sTeam='', sRobotFile='',
|
|
760
|
+
def createTestcaseTemplate(self, testcaseName, sDescription='',
|
|
761
|
+
sComponent='', sFID='', sTeam='', sRobotFile='',
|
|
759
762
|
sTestType='', sASIL='', sOwnerID='', sTCtemplate=None):
|
|
760
763
|
"""
|
|
761
764
|
Return testcase template from provided information.
|
|
@@ -801,25 +804,25 @@ Return testcase template from provided information.
|
|
|
801
804
|
* ``sTestType``
|
|
802
805
|
|
|
803
806
|
/ *Condition*: optional / *Type*: str / *Default*: '' /
|
|
804
|
-
|
|
807
|
+
|
|
805
808
|
Test type information.
|
|
806
809
|
|
|
807
810
|
* ``sASIL``
|
|
808
811
|
|
|
809
812
|
/ *Condition*: optional / *Type*: str / *Default*: '' /
|
|
810
|
-
|
|
813
|
+
|
|
811
814
|
ASIL information.
|
|
812
815
|
|
|
813
816
|
* ``sOwnerID``
|
|
814
817
|
|
|
815
818
|
/ *Condition*: optional / *Type*: str / *Default*: '' /
|
|
816
|
-
|
|
819
|
+
|
|
817
820
|
User ID of testcase owner.
|
|
818
821
|
|
|
819
822
|
* ``sTCtemplate``
|
|
820
823
|
|
|
821
824
|
/ *Condition*: optional / *Type*: str / *Default*: None /
|
|
822
|
-
|
|
825
|
+
|
|
823
826
|
Existing testcase template as xml string.
|
|
824
827
|
|
|
825
828
|
If not provided, template file under `RQM_templates` is used as default.
|
|
@@ -844,11 +847,11 @@ Return testcase template from provided information.
|
|
|
844
847
|
# prepare required data for template
|
|
845
848
|
testcaseTittle = testcaseName
|
|
846
849
|
|
|
847
|
-
# find nodes to change data
|
|
850
|
+
# find nodes to change data
|
|
848
851
|
oTittle = oTree.find(f'{{{self.NAMESPACES["ns3"]}}}title')
|
|
849
852
|
oDescription = oTree.find(f'{{{self.NAMESPACES["ns3"]}}}description')
|
|
850
853
|
oOwner = oTree.find(f'{{{self.NAMESPACES["ns5"]}}}owner')
|
|
851
|
-
|
|
854
|
+
|
|
852
855
|
# change nodes's data
|
|
853
856
|
oTittle.text = testcaseTittle
|
|
854
857
|
oDescription.text = sDescription
|
|
@@ -879,7 +882,7 @@ Return testcase template from provided information.
|
|
|
879
882
|
|
|
880
883
|
oASIL = oTree.find(f'{{{self.NAMESPACES["ns2"]}}}category[@term="ASIL relevant"]', nsmap)
|
|
881
884
|
if (oASIL != None) and sASIL:
|
|
882
|
-
oASIL.set('value', sASIL)
|
|
885
|
+
oASIL.set('value', sASIL)
|
|
883
886
|
|
|
884
887
|
# Modify custom attributes
|
|
885
888
|
oRequirementID = oTree.find(f'{{{self.NAMESPACES["ns2"]}}}customAttributes/{{{self.NAMESPACES["ns2"]}}}customAttribute/[{{{self.NAMESPACES["ns2"]}}}name="Requirement ID"]', nsmap)
|
|
@@ -920,7 +923,7 @@ Return testcase execution record template from provided information.
|
|
|
920
923
|
* ``testplanID``
|
|
921
924
|
|
|
922
925
|
/ *Condition*: required / *Type*: str /
|
|
923
|
-
|
|
926
|
+
|
|
924
927
|
Testplan ID for linking.
|
|
925
928
|
|
|
926
929
|
* ``confID``
|
|
@@ -932,13 +935,13 @@ Return testcase execution record template from provided information.
|
|
|
932
935
|
* ``sTeam``
|
|
933
936
|
|
|
934
937
|
/ *Condition*: optional / *Type*: str / *Default*: '' /
|
|
935
|
-
|
|
938
|
+
|
|
936
939
|
Team name for linking.
|
|
937
940
|
|
|
938
941
|
* ``sOwnerID``
|
|
939
942
|
|
|
940
943
|
/ *Condition*: optional / *Type*: str / *Default*: '' /
|
|
941
|
-
|
|
944
|
+
|
|
942
945
|
User ID of testcase owner.
|
|
943
946
|
|
|
944
947
|
**Returns:**
|
|
@@ -962,7 +965,7 @@ Return testcase execution record template from provided information.
|
|
|
962
965
|
testplanURL = self.integrationURL('testplan', testplanID)
|
|
963
966
|
testerURL = self.userURL(self.userID)
|
|
964
967
|
|
|
965
|
-
# find nodes to change data
|
|
968
|
+
# find nodes to change data
|
|
966
969
|
oTittle = oTree.find('ns3:title', nsmap)
|
|
967
970
|
oTestcase = oTree.find('ns2:testcase', nsmap)
|
|
968
971
|
oTestplan = oTree.find('ns2:testplan', nsmap)
|
|
@@ -994,8 +997,8 @@ Return testcase execution record template from provided information.
|
|
|
994
997
|
sTCERxml = etree.tostring(oTree)
|
|
995
998
|
return sTCERxml
|
|
996
999
|
|
|
997
|
-
def createExecutionResultTemplate(self, testcaseID, testcaseName, testplanID,
|
|
998
|
-
TCERID, resultState, startTime='', endTime='', duration='', testPC='',
|
|
1000
|
+
def createExecutionResultTemplate(self, testcaseID, testcaseName, testplanID,
|
|
1001
|
+
TCERID, resultState, startTime='', endTime='', duration='', testPC='',
|
|
999
1002
|
testBy='', lastlog='', buildrecordID='', sTeam='', sOwnerID=''):
|
|
1000
1003
|
"""
|
|
1001
1004
|
Return testcase execution result template from provided information.
|
|
@@ -1107,7 +1110,7 @@ Return testcase execution result template from provided information.
|
|
|
1107
1110
|
TCERURL = self.integrationURL('executionworkitem', TCERID)
|
|
1108
1111
|
testerURL = self.userURL(self.userID)
|
|
1109
1112
|
|
|
1110
|
-
# find nodes to change data
|
|
1113
|
+
# find nodes to change data
|
|
1111
1114
|
oTittle = oTree.find('ns3:title', nsmap)
|
|
1112
1115
|
oMachine = oTree.find('ns16:machine', nsmap)
|
|
1113
1116
|
oState = oTree.find('ns5:state', nsmap)
|
|
@@ -1137,9 +1140,9 @@ Return testcase execution result template from provided information.
|
|
|
1137
1140
|
oOwner.attrib['{%s}resource' % nsmap['ns7']] = self.userURL(sOwnerID)
|
|
1138
1141
|
elif oOwner.text == None or oOwner.text == '':
|
|
1139
1142
|
oOwner.text = self.userID
|
|
1140
|
-
oOwner.attrib['{%s}resource' % nsmap['ns7']] = testerURL
|
|
1143
|
+
oOwner.attrib['{%s}resource' % nsmap['ns7']] = testerURL
|
|
1141
1144
|
# currently assign user name is not worked
|
|
1142
|
-
# oTester.text = testBy
|
|
1145
|
+
# oTester.text = testBy
|
|
1143
1146
|
oTester.text = self.userID
|
|
1144
1147
|
oTester.attrib['{%s}resource' % nsmap['ns7']] = testerURL
|
|
1145
1148
|
oStarttime.text = str(startTime).replace(' ', 'T')
|
|
@@ -1180,7 +1183,7 @@ Return build record template from provided build name.
|
|
|
1180
1183
|
* ``buildName``
|
|
1181
1184
|
|
|
1182
1185
|
/ *Condition*: required / *Type*: str /
|
|
1183
|
-
|
|
1186
|
+
|
|
1184
1187
|
`Build Record` name.
|
|
1185
1188
|
|
|
1186
1189
|
**Returns:**
|
|
@@ -1211,7 +1214,7 @@ Return configuration - Test Environment template from provided configuration nam
|
|
|
1211
1214
|
* ``buildName``
|
|
1212
1215
|
|
|
1213
1216
|
/ *Condition*: required / *Type*: str /
|
|
1214
|
-
|
|
1217
|
+
|
|
1215
1218
|
Configuration - `Test Environment` name.
|
|
1216
1219
|
|
|
1217
1220
|
**Returns:**
|
|
@@ -1219,9 +1222,9 @@ Return configuration - Test Environment template from provided configuration nam
|
|
|
1219
1222
|
* ``sEnvironmentxml``
|
|
1220
1223
|
|
|
1221
1224
|
/ *Type*: str /
|
|
1222
|
-
|
|
1225
|
+
|
|
1223
1226
|
The xml test environment template as string.
|
|
1224
|
-
"""
|
|
1227
|
+
"""
|
|
1225
1228
|
sEnvironmentxml = ''
|
|
1226
1229
|
sTemplatePath = os.path.join(self.templatesDir, 'configuration.xml')
|
|
1227
1230
|
oTree = get_xml_tree(sTemplatePath, bdtd_validation=False)
|
|
@@ -1233,7 +1236,7 @@ Return configuration - Test Environment template from provided configuration nam
|
|
|
1233
1236
|
sEnvironmentxml = etree.tostring(oTree)
|
|
1234
1237
|
return sEnvironmentxml
|
|
1235
1238
|
|
|
1236
|
-
def createTSERTemplate(self, testsuiteID, testsuiteName, testplanID,
|
|
1239
|
+
def createTSERTemplate(self, testsuiteID, testsuiteName, testplanID,
|
|
1237
1240
|
confID='', sOwnerID=''):
|
|
1238
1241
|
"""
|
|
1239
1242
|
Return testsuite execution record (TSER) template from provided configuration name.
|
|
@@ -1277,9 +1280,9 @@ Return testsuite execution record (TSER) template from provided configuration na
|
|
|
1277
1280
|
/ *Type*: str /
|
|
1278
1281
|
|
|
1279
1282
|
The xml testsuite template as string.
|
|
1280
|
-
"""
|
|
1283
|
+
"""
|
|
1281
1284
|
sTSxml = ''
|
|
1282
|
-
sTemplatePath = os.path.join(self.templatesDir,
|
|
1285
|
+
sTemplatePath = os.path.join(self.templatesDir,
|
|
1283
1286
|
'suiteexecutionrecord.xml')
|
|
1284
1287
|
oTree = get_xml_tree(sTemplatePath, bdtd_validation=False)
|
|
1285
1288
|
root = oTree.getroot()
|
|
@@ -1289,7 +1292,7 @@ Return testsuite execution record (TSER) template from provided configuration na
|
|
|
1289
1292
|
testplanURL = self.integrationURL('testplan', testplanID)
|
|
1290
1293
|
testerURL = self.userURL(self.userID)
|
|
1291
1294
|
|
|
1292
|
-
# find nodes to change data
|
|
1295
|
+
# find nodes to change data
|
|
1293
1296
|
nsmap = oTree.getroot().nsmap
|
|
1294
1297
|
oTittle = oTree.find('ns4:title', nsmap)
|
|
1295
1298
|
oTestsuite = oTree.find('ns2:testsuite', nsmap)
|
|
@@ -1300,7 +1303,7 @@ Return testsuite execution record (TSER) template from provided configuration na
|
|
|
1300
1303
|
oTittle.text = TSERTittle
|
|
1301
1304
|
oTestsuite.attrib['href'] = testsuiteURL
|
|
1302
1305
|
oTestplan.attrib['href'] = testplanURL
|
|
1303
|
-
# Incase not specify owner in template or input data,
|
|
1306
|
+
# Incase not specify owner in template or input data,
|
|
1304
1307
|
# set its value as provided user in cli
|
|
1305
1308
|
if sOwnerID:
|
|
1306
1309
|
oOwner.text = sOwnerID
|
|
@@ -1319,8 +1322,8 @@ Return testsuite execution record (TSER) template from provided configuration na
|
|
|
1319
1322
|
sTSxml = etree.tostring(oTree)
|
|
1320
1323
|
return sTSxml
|
|
1321
1324
|
|
|
1322
|
-
def createTestsuiteResultTemplate(self, testsuiteID, testsuiteName, TSERID,
|
|
1323
|
-
lTCER, lTCResults, startTime='',
|
|
1325
|
+
def createTestsuiteResultTemplate(self, testsuiteID, testsuiteName, TSERID,
|
|
1326
|
+
lTCER, lTCResults, startTime='',
|
|
1324
1327
|
endTime='', duration='', sOwnerID=''):
|
|
1325
1328
|
"""
|
|
1326
1329
|
Return testsuite execution result template from provided configuration name.
|
|
@@ -1388,7 +1391,7 @@ Return testsuite execution result template from provided configuration name.
|
|
|
1388
1391
|
/ *Type*: str /
|
|
1389
1392
|
|
|
1390
1393
|
The xml testsuite result template as string.
|
|
1391
|
-
"""
|
|
1394
|
+
"""
|
|
1392
1395
|
sTSResultxml = ''
|
|
1393
1396
|
sTemplatePath = os.path.join(self.templatesDir, 'testsuitelog.xml')
|
|
1394
1397
|
oTree = get_xml_tree(sTemplatePath, bdtd_validation=False)
|
|
@@ -1405,7 +1408,7 @@ Return testsuite execution result template from provided configuration name.
|
|
|
1405
1408
|
if duration == '':
|
|
1406
1409
|
duration = (time.mktime(endTime.timetuple()) - time.mktime(startTime.timetuple()))*1000
|
|
1407
1410
|
|
|
1408
|
-
# find nodes to change data
|
|
1411
|
+
# find nodes to change data
|
|
1409
1412
|
root = oTree.getroot()
|
|
1410
1413
|
nsmap = root.nsmap
|
|
1411
1414
|
oTittle = oTree.find('ns4:title', nsmap)
|
|
@@ -1424,7 +1427,7 @@ Return testsuite execution result template from provided configuration name.
|
|
|
1424
1427
|
oTittle.text = resultTittle
|
|
1425
1428
|
oTestsuite.attrib['href'] = testsuiteURL
|
|
1426
1429
|
oTSER.attrib['href'] = TSERURL
|
|
1427
|
-
# Incase not specify owner in template or input data,
|
|
1430
|
+
# Incase not specify owner in template or input data,
|
|
1428
1431
|
# set its value as provided user in cli
|
|
1429
1432
|
if sOwnerID:
|
|
1430
1433
|
oOwner.text = sOwnerID
|
|
@@ -1451,7 +1454,7 @@ Return testsuite execution result template from provided configuration name.
|
|
|
1451
1454
|
sTCResultURL = self.integrationURL('executionresult', lTCResults[idx])
|
|
1452
1455
|
oExecutionResult.set('href', sTCResultURL)
|
|
1453
1456
|
root.append(oExecutionResult)
|
|
1454
|
-
|
|
1457
|
+
|
|
1455
1458
|
# return xml template as string
|
|
1456
1459
|
sTSResultxml = etree.tostring(oTree)
|
|
1457
1460
|
return sTSResultxml
|
|
@@ -1491,25 +1494,25 @@ Create new resource with provided data from template by POST method.
|
|
|
1491
1494
|
.. code:: python
|
|
1492
1495
|
|
|
1493
1496
|
{
|
|
1494
|
-
'success' : False,
|
|
1495
|
-
'id': None,
|
|
1496
|
-
'message': '',
|
|
1497
|
+
'success' : False,
|
|
1498
|
+
'id': None,
|
|
1499
|
+
'message': '',
|
|
1497
1500
|
'status_code': ''
|
|
1498
1501
|
}
|
|
1499
1502
|
|
|
1500
1503
|
"""
|
|
1501
1504
|
returnObj = {
|
|
1502
|
-
'success' : False,
|
|
1503
|
-
'id': None,
|
|
1504
|
-
'message': '',
|
|
1505
|
+
'success' : False,
|
|
1506
|
+
'id': None,
|
|
1507
|
+
'message': '',
|
|
1505
1508
|
'status_code': ''
|
|
1506
1509
|
}
|
|
1507
1510
|
if(self.headers['X-Jazz-CSRF-Prevent'] == ''):
|
|
1508
1511
|
returnObj['message'] = "JSESSIONID is missing for RQM resource's creation"
|
|
1509
1512
|
return returnObj
|
|
1510
1513
|
|
|
1511
|
-
res = self.session.post(self.integrationURL(resourceType),
|
|
1512
|
-
allow_redirects=True, verify=False,
|
|
1514
|
+
res = self.session.post(self.integrationURL(resourceType),
|
|
1515
|
+
allow_redirects=True, verify=False,
|
|
1513
1516
|
data=content, headers=self.headers)
|
|
1514
1517
|
returnObj['status_code'] = res.status_code
|
|
1515
1518
|
# Check whether successful response
|
|
@@ -1521,7 +1524,7 @@ Create new resource with provided data from template by POST method.
|
|
|
1521
1524
|
returnObj['id'] = res.headers['Content-Location'].replace(sRemove, '')
|
|
1522
1525
|
|
|
1523
1526
|
# On IBM Engineering Test Management Version: 7.0.2
|
|
1524
|
-
# When trying to create new TCER but it is existing for testcase and testplan,
|
|
1527
|
+
# When trying to create new TCER but it is existing for testcase and testplan,
|
|
1525
1528
|
# the response is 200 instead of 303 as previous RQM version 6.x.x
|
|
1526
1529
|
# Below step is trying to get existing TCER ID from response <200>
|
|
1527
1530
|
elif res.status_code == 200 and res.text:
|
|
@@ -1531,11 +1534,11 @@ Create new resource with provided data from template by POST method.
|
|
|
1531
1534
|
returnObj['message'] = "Extract ID information from response failed. Reason: %s" % str(error)
|
|
1532
1535
|
else:
|
|
1533
1536
|
### Get new creation ID from response
|
|
1534
|
-
try:
|
|
1537
|
+
try:
|
|
1535
1538
|
# try to get the web ID (internalID) from response of POST method
|
|
1536
1539
|
if res.text and (res.text != ''):
|
|
1537
1540
|
returnObj['id'] = self.webIDfromResponse(res.text)
|
|
1538
|
-
# The externalID of new resource is responsed in 'Content-Location'
|
|
1541
|
+
# The externalID of new resource is responsed in 'Content-Location'
|
|
1539
1542
|
# from response headers
|
|
1540
1543
|
elif res.headers['Content-Location'] != '':
|
|
1541
1544
|
returnObj['id'] = res.headers['Content-Location']
|
|
@@ -1578,9 +1581,9 @@ Create new build record.
|
|
|
1578
1581
|
.. code:: python
|
|
1579
1582
|
|
|
1580
1583
|
{
|
|
1581
|
-
'success' : False,
|
|
1582
|
-
'id': None,
|
|
1583
|
-
'message': '',
|
|
1584
|
+
'success' : False,
|
|
1585
|
+
'id': None,
|
|
1586
|
+
'message': '',
|
|
1584
1587
|
'status_code': ''
|
|
1585
1588
|
}
|
|
1586
1589
|
|
|
@@ -1589,9 +1592,9 @@ Create new build record.
|
|
|
1589
1592
|
returnObj = {'success' : False, 'id': None, 'message': '', 'status_code': ''}
|
|
1590
1593
|
if (sBuildSWVersion not in self.dBuildVersion.values()) or forceCreate:
|
|
1591
1594
|
sBuildTemplate = self.createBuildRecordTemplate(sBuildSWVersion)
|
|
1592
|
-
returnObj = self.createResource('buildrecord', sBuildTemplate)
|
|
1595
|
+
returnObj = self.createResource('buildrecord', sBuildTemplate)
|
|
1593
1596
|
if returnObj['success']:
|
|
1594
|
-
# store existing build ID for next verification
|
|
1597
|
+
# store existing build ID for next verification
|
|
1595
1598
|
self.dBuildVersion[returnObj['id']] = sBuildSWVersion
|
|
1596
1599
|
else:
|
|
1597
1600
|
idx = list(self.dBuildVersion.values()).index(sBuildSWVersion)
|
|
@@ -1631,9 +1634,9 @@ Create new configuration - test environment.
|
|
|
1631
1634
|
.. code:: python
|
|
1632
1635
|
|
|
1633
1636
|
{
|
|
1634
|
-
'success' : False,
|
|
1635
|
-
'id': None,
|
|
1636
|
-
'message': '',
|
|
1637
|
+
'success' : False,
|
|
1638
|
+
'id': None,
|
|
1639
|
+
'message': '',
|
|
1637
1640
|
'status_code': ''
|
|
1638
1641
|
}
|
|
1639
1642
|
|
|
@@ -1645,7 +1648,7 @@ Create new configuration - test environment.
|
|
|
1645
1648
|
sConfTemplate = self.createConfigurationTemplate(sConfigurationName)
|
|
1646
1649
|
returnObj = self.createResource('configuration', sConfTemplate)
|
|
1647
1650
|
if returnObj['success']:
|
|
1648
|
-
# store existing configuration ID for next verification
|
|
1651
|
+
# store existing configuration ID for next verification
|
|
1649
1652
|
self.dConfiguation[returnObj['id']] = sConfigurationName
|
|
1650
1653
|
else:
|
|
1651
1654
|
idx = list(self.dConfiguation.values()).index(sConfigurationName)
|
|
@@ -1712,13 +1715,13 @@ Link list of test cases to provided testplan ID.
|
|
|
1712
1715
|
List of testcase(s) to be linked with given testplan.
|
|
1713
1716
|
|
|
1714
1717
|
If not provide, `lTestcaseIDs` property will be used as list of testcase.
|
|
1715
|
-
|
|
1718
|
+
|
|
1716
1719
|
**Returns:**
|
|
1717
1720
|
|
|
1718
1721
|
* ``returnObj``
|
|
1719
1722
|
|
|
1720
1723
|
/ *Type*: dict /
|
|
1721
|
-
|
|
1724
|
+
|
|
1722
1725
|
Response dictionary which contains status and error message.
|
|
1723
1726
|
|
|
1724
1727
|
Example:
|
|
@@ -1726,7 +1729,7 @@ Link list of test cases to provided testplan ID.
|
|
|
1726
1729
|
.. code:: python
|
|
1727
1730
|
|
|
1728
1731
|
{
|
|
1729
|
-
'success' : False,
|
|
1732
|
+
'success' : False,
|
|
1730
1733
|
'message': ''
|
|
1731
1734
|
}
|
|
1732
1735
|
|
|
@@ -1734,13 +1737,13 @@ Link list of test cases to provided testplan ID.
|
|
|
1734
1737
|
returnObj = {'success' : False, 'message': ''}
|
|
1735
1738
|
if lTestcases == None:
|
|
1736
1739
|
lTestcases = self.lTestcaseIDs
|
|
1737
|
-
if len(lTestcases):
|
|
1740
|
+
if len(lTestcases):
|
|
1738
1741
|
resTestplanData = self.getResourceByID('testplan', testplanID)
|
|
1739
1742
|
oTree = get_xml_tree(BytesIO(str(resTestplanData.text).encode()),bdtd_validation=False)
|
|
1740
1743
|
# RQM XML response using namespace for nodes
|
|
1741
1744
|
# use namespace mapping from root for access response XML
|
|
1742
1745
|
root = oTree.getroot()
|
|
1743
|
-
|
|
1746
|
+
|
|
1744
1747
|
for sTCID in lTestcases:
|
|
1745
1748
|
sTestcaseURL = self.integrationURL('testcase', sTCID)
|
|
1746
1749
|
oTC = etree.Element('{http://jazz.net/xmlns/alm/qm/v0.1/}testcase', nsmap=root.nsmap)
|
|
@@ -1755,7 +1758,7 @@ Link list of test cases to provided testplan ID.
|
|
|
1755
1758
|
returnObj['message'] = str(resUpdateTestplan.reason)
|
|
1756
1759
|
else:
|
|
1757
1760
|
returnObj['message'] = "No testcase for linking."
|
|
1758
|
-
return returnObj
|
|
1761
|
+
return returnObj
|
|
1759
1762
|
|
|
1760
1763
|
def linkListTestcase2Testsuite(self, testsuiteID, lTestcases=None):
|
|
1761
1764
|
"""
|
|
@@ -1776,13 +1779,13 @@ Link list of test cases to provided testsuite ID
|
|
|
1776
1779
|
List of testcase(s) to be linked with given testplan.
|
|
1777
1780
|
|
|
1778
1781
|
If not provide, `lTestcaseIDs` property will be used as list of testcase.
|
|
1779
|
-
|
|
1782
|
+
|
|
1780
1783
|
**Returns:**
|
|
1781
1784
|
|
|
1782
1785
|
* ``returnObj``
|
|
1783
1786
|
|
|
1784
1787
|
/ *Type*: dict /
|
|
1785
|
-
|
|
1788
|
+
|
|
1786
1789
|
Response dictionary which contains status and error message.
|
|
1787
1790
|
|
|
1788
1791
|
Example:
|
|
@@ -1790,7 +1793,7 @@ Link list of test cases to provided testsuite ID
|
|
|
1790
1793
|
.. code:: python
|
|
1791
1794
|
|
|
1792
1795
|
{
|
|
1793
|
-
'success' : False,
|
|
1796
|
+
'success' : False,
|
|
1794
1797
|
'message': ''
|
|
1795
1798
|
}
|
|
1796
1799
|
|
|
@@ -1798,7 +1801,7 @@ Link list of test cases to provided testsuite ID
|
|
|
1798
1801
|
returnObj = {'success' : False, 'message': ''}
|
|
1799
1802
|
if lTestcases == None:
|
|
1800
1803
|
lTestcases = self.lTestcaseIDs
|
|
1801
|
-
if len(lTestcases):
|
|
1804
|
+
if len(lTestcases):
|
|
1802
1805
|
resTestsuiteData = self.getResourceByID('testsuite', testsuiteID)
|
|
1803
1806
|
oTree=get_xml_tree(BytesIO(str(resTestsuiteData.text).encode()),bdtd_validation=False)
|
|
1804
1807
|
# RQM XML response using namespace for nodes
|
|
@@ -1823,4 +1826,4 @@ Link list of test cases to provided testsuite ID
|
|
|
1823
1826
|
returnObj['message'] = str(resUpdateTestsuite.reason)
|
|
1824
1827
|
else:
|
|
1825
1828
|
returnObj['message'] = "No testcase for linking."
|
|
1826
|
-
return returnObj
|
|
1829
|
+
return returnObj
|
RobotLog2RQM/RobotLog2RQM.pdf
CHANGED
|
Binary file
|
RobotLog2RQM/__init__.py
CHANGED
RobotLog2RQM/__main__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2020-
|
|
1
|
+
# Copyright 2020-2023 Robert Bosch GmbH
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -14,4 +14,4 @@
|
|
|
14
14
|
from .robotlog2rqm import RobotLog2RQM
|
|
15
15
|
|
|
16
16
|
if __name__ == "__main__":
|
|
17
|
-
RobotLog2RQM()
|
|
17
|
+
RobotLog2RQM()
|
RobotLog2RQM/robotlog2rqm.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2020-
|
|
1
|
+
# Copyright 2020-2023 Robert Bosch GmbH
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
#
|
|
20
20
|
# This tool is used to parse the robot framework results output.xml
|
|
21
21
|
# then import them into RQM - IBM Rational Quality Manager
|
|
22
|
-
#
|
|
22
|
+
#
|
|
23
23
|
# History:
|
|
24
|
-
#
|
|
24
|
+
#
|
|
25
25
|
# 2020-01-08:
|
|
26
26
|
# - initial version
|
|
27
27
|
#
|
|
@@ -41,7 +41,8 @@ from RobotLog2RQM.version import VERSION, VERSION_DATE
|
|
|
41
41
|
DRESULT_MAPPING = {
|
|
42
42
|
"PASS": "Passed",
|
|
43
43
|
"FAIL": "Failed",
|
|
44
|
-
"UNKNOWN": "Inconclusive"
|
|
44
|
+
"UNKNOWN": "Inconclusive",
|
|
45
|
+
"SKIP": "Blocked"
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
DEFAULT_METADATA = {
|
|
@@ -142,7 +143,7 @@ Write log message to console/file output.
|
|
|
142
143
|
/ *Condition*: optional / *Type*: int / *Default*: 0 /
|
|
143
144
|
|
|
144
145
|
Offset indent.
|
|
145
|
-
|
|
146
|
+
|
|
146
147
|
**Returns:**
|
|
147
148
|
|
|
148
149
|
(*no returns*)
|
|
@@ -160,7 +161,7 @@ Write log message to console/file output.
|
|
|
160
161
|
def log_warning(cls, msg):
|
|
161
162
|
"""
|
|
162
163
|
Write warning message to console/file output.
|
|
163
|
-
|
|
164
|
+
|
|
164
165
|
**Arguments:**
|
|
165
166
|
|
|
166
167
|
* ``msg``
|
|
@@ -210,7 +211,7 @@ def get_from_tags(lTags, reInfo):
|
|
|
210
211
|
"""
|
|
211
212
|
Extract testcase information from tags.
|
|
212
213
|
|
|
213
|
-
Example:
|
|
214
|
+
Example:
|
|
214
215
|
TCID-xxxx, FID-xxxx, ...
|
|
215
216
|
|
|
216
217
|
**Arguments:**
|
|
@@ -232,7 +233,7 @@ Example:
|
|
|
232
233
|
* ``lInfo``
|
|
233
234
|
|
|
234
235
|
/ *Type*: list /
|
|
235
|
-
|
|
236
|
+
|
|
236
237
|
List of expected information (ID)
|
|
237
238
|
"""
|
|
238
239
|
lInfo = []
|
|
@@ -266,7 +267,7 @@ Convert time string to datetime.
|
|
|
266
267
|
tp=re.findall(r"(\d{4})(\d{2})(\d{2})\s(\d+):(\d+):(\d+)\.(\d+)",time)[0]
|
|
267
268
|
tp=list(map(int,tp))
|
|
268
269
|
dt=datetime.datetime(tp[0],tp[1],tp[2],tp[3],tp[4],tp[5],tp[6])
|
|
269
|
-
return dt
|
|
270
|
+
return dt
|
|
270
271
|
|
|
271
272
|
def __process_commandline():
|
|
272
273
|
"""
|
|
@@ -300,24 +301,24 @@ Avalable arguments in command line:
|
|
|
300
301
|
|
|
301
302
|
cmdParser=argparse.ArgumentParser(prog=PROG_NAME, description=PROG_DESC)
|
|
302
303
|
|
|
303
|
-
cmdParser.add_argument('-v', '--version', action='version',
|
|
304
|
+
cmdParser.add_argument('-v', '--version', action='version',
|
|
304
305
|
version=f'v{VERSION} ({VERSION_DATE})',
|
|
305
306
|
help='Version of the RobotLog2RQM importer.')
|
|
306
|
-
cmdParser.add_argument('resultxmlfile', type=str,
|
|
307
|
+
cmdParser.add_argument('resultxmlfile', type=str,
|
|
307
308
|
help='absolute or relative path to the xml result file or directory of result files to be imported.')
|
|
308
309
|
cmdParser.add_argument('host', type=str, help='RQM host url.')
|
|
309
310
|
cmdParser.add_argument('project', type=str, help='project on RQM.')
|
|
310
311
|
cmdParser.add_argument('user', type=str, help='user for RQM login.')
|
|
311
312
|
cmdParser.add_argument('password', type=str, help='password for RQM login.')
|
|
312
|
-
cmdParser.add_argument('testplan', type=str,
|
|
313
|
+
cmdParser.add_argument('testplan', type=str,
|
|
313
314
|
help='testplan ID for this execution.')
|
|
314
|
-
cmdParser.add_argument('--recursive',action="store_true",
|
|
315
|
+
cmdParser.add_argument('--recursive',action="store_true",
|
|
315
316
|
help='if set, then the path is searched recursively for log files to be imported.')
|
|
316
|
-
cmdParser.add_argument('--createmissing', action="store_true",
|
|
317
|
+
cmdParser.add_argument('--createmissing', action="store_true",
|
|
317
318
|
help='if set, then all testcases without tcid are created when importing.')
|
|
318
|
-
cmdParser.add_argument('--updatetestcase', action="store_true",
|
|
319
|
+
cmdParser.add_argument('--updatetestcase', action="store_true",
|
|
319
320
|
help='if set, then testcase information on RQM will be updated bases on robot testfile.')
|
|
320
|
-
cmdParser.add_argument('--dryrun',action="store_true",
|
|
321
|
+
cmdParser.add_argument('--dryrun',action="store_true",
|
|
321
322
|
help='if set, then verify all input arguments (includes RQM authentication) and show what would be done.')
|
|
322
323
|
|
|
323
324
|
return cmdParser.parse_args()
|
|
@@ -327,7 +328,7 @@ def process_suite_metadata(suite, default_metadata=DEFAULT_METADATA):
|
|
|
327
328
|
Try to find metadata information from all suite levels.
|
|
328
329
|
|
|
329
330
|
Metadata at top suite level has a highest priority.
|
|
330
|
-
|
|
331
|
+
|
|
331
332
|
**Arguments:**
|
|
332
333
|
|
|
333
334
|
* ``suite``
|
|
@@ -357,7 +358,7 @@ Metadata at top suite level has a highest priority.
|
|
|
357
358
|
# The higher suite level metadata have higher priority
|
|
358
359
|
if suite.metadata != None:
|
|
359
360
|
dMetadata = process_metadata(suite.metadata, dMetadata)
|
|
360
|
-
|
|
361
|
+
|
|
361
362
|
return dMetadata
|
|
362
363
|
|
|
363
364
|
def process_metadata(metadata, default_metadata=DEFAULT_METADATA):
|
|
@@ -381,10 +382,10 @@ Extract metadata from suite result bases on DEFAULT_METADATA.
|
|
|
381
382
|
**Returns:**
|
|
382
383
|
|
|
383
384
|
* ``dMetadata``
|
|
384
|
-
|
|
385
|
+
|
|
385
386
|
/ *Type*: dict /
|
|
386
|
-
|
|
387
|
-
Dictionary of Metadata information.
|
|
387
|
+
|
|
388
|
+
Dictionary of Metadata information.
|
|
388
389
|
"""
|
|
389
390
|
dMetadata = dict(default_metadata)
|
|
390
391
|
for key in dMetadata.keys():
|
|
@@ -414,7 +415,7 @@ Process robot suite for importing to RQM.
|
|
|
414
415
|
|
|
415
416
|
**Returns:**
|
|
416
417
|
|
|
417
|
-
(*no returns*)
|
|
418
|
+
(*no returns*)
|
|
418
419
|
"""
|
|
419
420
|
if len(list(suite.suites)) > 0:
|
|
420
421
|
for subsuite in suite.suites:
|
|
@@ -427,7 +428,7 @@ Process robot suite for importing to RQM.
|
|
|
427
428
|
for key in suite.parent.metadata.keys():
|
|
428
429
|
if key not in suite.metadata:
|
|
429
430
|
suite.metadata[key] = suite.parent.metadata[key]
|
|
430
|
-
|
|
431
|
+
|
|
431
432
|
if len(list(suite.tests)) > 0:
|
|
432
433
|
for test in suite.tests:
|
|
433
434
|
process_test(RQMClient, test)
|
|
@@ -452,14 +453,14 @@ Process robot test for importing to RQM.
|
|
|
452
453
|
|
|
453
454
|
**Returns:**
|
|
454
455
|
|
|
455
|
-
(*no returns*)
|
|
456
|
+
(*no returns*)
|
|
456
457
|
"""
|
|
457
458
|
Logger.log(f"Process test: {test.name}")
|
|
458
459
|
|
|
459
460
|
# Avoid create resources with dryrun
|
|
460
461
|
if Logger.dryrun:
|
|
461
462
|
return
|
|
462
|
-
|
|
463
|
+
|
|
463
464
|
# Parse test case data:
|
|
464
465
|
_tc_fid = ";".join(get_from_tags(test.tags, "fid-(.+)"))
|
|
465
466
|
lTCIDTags = get_from_tags(test.tags, "tcid-(.+)")
|
|
@@ -499,9 +500,9 @@ Process robot test for importing to RQM.
|
|
|
499
500
|
# Create new testcase on RQM
|
|
500
501
|
# Update dMappingTCID (to update *.robot testfile with generated ID - Not implemented yet).
|
|
501
502
|
if _tc_createmissing:
|
|
502
|
-
oTCTemplate = RQMClient.createTestcaseTemplate( _tc_name,
|
|
503
|
+
oTCTemplate = RQMClient.createTestcaseTemplate( _tc_name,
|
|
503
504
|
_tc_desc,
|
|
504
|
-
_tc_cmpt,
|
|
505
|
+
_tc_cmpt,
|
|
505
506
|
_tc_fid,
|
|
506
507
|
_tc_team,
|
|
507
508
|
_tc_link)
|
|
@@ -529,9 +530,9 @@ Process robot test for importing to RQM.
|
|
|
529
530
|
if _tc_update:
|
|
530
531
|
resTC = RQMClient.getResourceByID('testcase', _tc_id)
|
|
531
532
|
if resTC.status_code == 200 and resTC.text:
|
|
532
|
-
oTCTemplate = RQMClient.createTestcaseTemplate( _tc_name,
|
|
533
|
+
oTCTemplate = RQMClient.createTestcaseTemplate( _tc_name,
|
|
533
534
|
_tc_desc,
|
|
534
|
-
_tc_cmpt,
|
|
535
|
+
_tc_cmpt,
|
|
535
536
|
_tc_fid,
|
|
536
537
|
_tc_team,
|
|
537
538
|
_tc_link,
|
|
@@ -552,7 +553,7 @@ Process robot test for importing to RQM.
|
|
|
552
553
|
_tc_config_id,
|
|
553
554
|
_tc_team)
|
|
554
555
|
res = RQMClient.createResource('executionworkitem', oTCERTemplate)
|
|
555
|
-
_tc_tcer_id = res['id']
|
|
556
|
+
_tc_tcer_id = res['id']
|
|
556
557
|
if res['success']:
|
|
557
558
|
Logger.log(f"Created TCER with ID '{_tc_tcer_id}' successfully.")
|
|
558
559
|
elif (res['status_code'] == 303 or res['status_code'] == 200) and res['id'] != '':
|
|
@@ -604,7 +605,7 @@ Flow to import Robot results to RQM:
|
|
|
604
605
|
1. Process provided arguments from command line
|
|
605
606
|
2. Login Rational Quality Management (RQM)
|
|
606
607
|
3. Parse Robot results
|
|
607
|
-
4. Import results into RQM
|
|
608
|
+
4. Import results into RQM
|
|
608
609
|
5. Link all executed testcases to provided testplan/testsuite ID
|
|
609
610
|
|
|
610
611
|
**Arguments:**
|
|
@@ -640,7 +641,7 @@ Flow to import Robot results to RQM:
|
|
|
640
641
|
if os.path.exists(args.resultxmlfile):
|
|
641
642
|
sLogFileType="PATH"
|
|
642
643
|
if os.path.isfile(args.resultxmlfile):
|
|
643
|
-
sLogFileType="FILE"
|
|
644
|
+
sLogFileType="FILE"
|
|
644
645
|
else:
|
|
645
646
|
Logger.log_error(f"Given resultxmlfile is not existing: '{args.resultxmlfile}'.", fatal_error=True)
|
|
646
647
|
|
|
@@ -681,7 +682,7 @@ Flow to import Robot results to RQM:
|
|
|
681
682
|
except Exception as reason:
|
|
682
683
|
Logger.log_error(f"Could not login to RQM: '{str(reason)}'.")
|
|
683
684
|
|
|
684
|
-
# 4. Import results into RQM
|
|
685
|
+
# 4. Import results into RQM
|
|
685
686
|
try:
|
|
686
687
|
metadata_info = process_suite_metadata(result.suite)
|
|
687
688
|
if not metadata_info['version_sw']:
|
|
@@ -692,9 +693,9 @@ Flow to import Robot results to RQM:
|
|
|
692
693
|
if args.dryrun:
|
|
693
694
|
metadata_info['version_sw'] = None
|
|
694
695
|
metadata_info['project'] = None
|
|
695
|
-
RQMClient.config(args.testplan, metadata_info['version_sw'],
|
|
696
|
+
RQMClient.config(args.testplan, metadata_info['version_sw'],
|
|
696
697
|
metadata_info['project'], args.createmissing, args.updatetestcase)
|
|
697
|
-
# Process suite for importing
|
|
698
|
+
# Process suite for importing
|
|
698
699
|
process_suite(RQMClient, result.suite)
|
|
699
700
|
|
|
700
701
|
# Link all imported testcase ID(s) with testplan
|
|
@@ -712,4 +713,4 @@ Flow to import Robot results to RQM:
|
|
|
712
713
|
Logger.log("All test results have been imported to RQM successfully.!")
|
|
713
714
|
|
|
714
715
|
if __name__=="__main__":
|
|
715
|
-
RobotLog2RQM()
|
|
716
|
+
RobotLog2RQM()
|
RobotLog2RQM/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# **************************************************************************************************************
|
|
2
2
|
#
|
|
3
|
-
# Copyright 2020-
|
|
3
|
+
# Copyright 2020-2023 Robert Bosch GmbH
|
|
4
4
|
#
|
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
6
|
# you may not use this file except in compliance with the License.
|
|
@@ -18,6 +18,6 @@
|
|
|
18
18
|
#
|
|
19
19
|
# Version and date of RobotLog2RQM
|
|
20
20
|
#
|
|
21
|
-
VERSION = "1.2.
|
|
22
|
-
VERSION_DATE = "
|
|
21
|
+
VERSION = "1.2.4"
|
|
22
|
+
VERSION_DATE = "11.06.2024"
|
|
23
23
|
|
{robotframework_robotlog2rqm-1.2.1.dist-info → robotframework_robotlog2rqm-1.2.4.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: robotframework-robotlog2rqm
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.4
|
|
4
4
|
Summary: Imports robot result(s) to IBM Rational Quality Manager (RQM)
|
|
5
5
|
Home-page: https://github.com/test-fullautomation/robotframework-robotlog2rqm
|
|
6
6
|
Author: Tran Duy Ngoan
|
|
@@ -132,15 +132,15 @@ Use below command to get tools\'s usage:
|
|
|
132
132
|
|
|
133
133
|
The usage should be showed as below:
|
|
134
134
|
|
|
135
|
-
usage: RobotLog2RQM (RobotXMLResult to RQM importer) [-h] [-v] [--recursive]
|
|
136
|
-
[--createmissing] [--updatetestcase] [--dryrun]
|
|
135
|
+
usage: RobotLog2RQM (RobotXMLResult to RQM importer) [-h] [-v] [--recursive]
|
|
136
|
+
[--createmissing] [--updatetestcase] [--dryrun]
|
|
137
137
|
resultxmlfile host project user password testplan
|
|
138
138
|
|
|
139
|
-
RobotLog2RQM imports XML result files (default: output.xml) generated by the
|
|
139
|
+
RobotLog2RQM imports XML result files (default: output.xml) generated by the
|
|
140
140
|
Robot Framework into an IBM Rational Quality Manager.
|
|
141
141
|
|
|
142
142
|
positional arguments:
|
|
143
|
-
resultxmlfile absolute or relative path to the xml result file
|
|
143
|
+
resultxmlfile absolute or relative path to the xml result file
|
|
144
144
|
or directory of result files to be imported.
|
|
145
145
|
host RQM host url.
|
|
146
146
|
project project on RQM.
|
|
@@ -151,13 +151,13 @@ The usage should be showed as below:
|
|
|
151
151
|
optional arguments:
|
|
152
152
|
-h, --help show this help message and exit
|
|
153
153
|
-v, --version Version of the RobotLog2RQM importer.
|
|
154
|
-
--recursive if set, then the path is searched recursively for
|
|
154
|
+
--recursive if set, then the path is searched recursively for
|
|
155
155
|
log files to be imported.
|
|
156
|
-
--createmissing if set, then all testcases without tcid are created
|
|
156
|
+
--createmissing if set, then all testcases without tcid are created
|
|
157
157
|
when importing.
|
|
158
|
-
--updatetestcase if set, then testcase information on RQM will be updated
|
|
158
|
+
--updatetestcase if set, then testcase information on RQM will be updated
|
|
159
159
|
bases on robot testfile.
|
|
160
|
-
--dryrun if set, then verify all input arguments
|
|
160
|
+
--dryrun if set, then verify all input arguments
|
|
161
161
|
(includes RQM authentication) and show what would be done.
|
|
162
162
|
|
|
163
163
|
The below command is simple usage witth all required arguments to import
|
|
@@ -189,12 +189,12 @@ importing into RQM:
|
|
|
189
189
|
|
|
190
190
|
*** Test Cases ***
|
|
191
191
|
Testcase 01
|
|
192
|
-
[Documentation] This test is traceable with provided tcid
|
|
192
|
+
[Documentation] This test is traceable with provided tcid
|
|
193
193
|
[Tags] TCID-1001 FID-112 FID-111 robotfile-https://github.com/test-fullautomation
|
|
194
194
|
Log This is Testcase 01
|
|
195
195
|
|
|
196
196
|
Testcase 02
|
|
197
|
-
[Documentation] This new testcase will be created if --createmissing argument
|
|
197
|
+
[Documentation] This new testcase will be created if --createmissing argument
|
|
198
198
|
... is provided when importing
|
|
199
199
|
[Tags] FID-113 robotfile-https://github.com/test-fullautomation
|
|
200
200
|
Log This is Testcase 02
|
|
@@ -246,7 +246,7 @@ Contributors
|
|
|
246
246
|
License
|
|
247
247
|
-------
|
|
248
248
|
|
|
249
|
-
Copyright 2020-
|
|
249
|
+
Copyright 2020-2024 Robert Bosch GmbH
|
|
250
250
|
|
|
251
251
|
Licensed under the Apache License, Version 2.0 (the \"License\"); you
|
|
252
252
|
may not use this file except in compliance with the License. You may
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
RobotLog2RQM/CRQM.py,sha256=yj5q-_Mj_cB4vpwn1G5PzAQFTc756CYB1kIN9xAAA84,54877
|
|
2
|
+
RobotLog2RQM/RobotLog2RQM.pdf,sha256=iaFtTHrkGNTP2G80qrbubDGBT7-fHvIhFJKNAZ_4Wnc,229406
|
|
3
|
+
RobotLog2RQM/__init__.py,sha256=YKDTJjDsnQkr5X-gjjO8opwKUVKm6kc8sIUpURYMk48,596
|
|
4
|
+
RobotLog2RQM/__main__.py,sha256=JabttEncy80antJWeGVmjoXyiF1DyXxkxdW4xLuHzT0,681
|
|
5
|
+
RobotLog2RQM/robotlog2rqm.py,sha256=MIxcZOShuY4WhJrygEPz9ez4sExnqRChE8bS5KT7e_A,22809
|
|
6
|
+
RobotLog2RQM/version.py,sha256=yqnuwM8tX61YINvlY0GOtFka-SLaeHKFTqJT9oju36M,917
|
|
7
|
+
RobotLog2RQM/RQM_templates/buildrecord.xml,sha256=uGot7pNOjPR8do0JsJi0Lz3OCU9NMhODRd428QgvHh4,1498
|
|
8
|
+
RobotLog2RQM/RQM_templates/configuration.xml,sha256=NrFDv51fuGhgeMiZuRhQ5q_UJ0u_pWzdxisIF5AJs74,1378
|
|
9
|
+
RobotLog2RQM/RQM_templates/executionresult.xml,sha256=WTp4qDk29peBc0ll6GHVXX_kF_YBsOVjy9vBzoz7_2k,2160
|
|
10
|
+
RobotLog2RQM/RQM_templates/executionworkitem.xml,sha256=3GYO-nvXcG-HDQZnDzGwYZSQOWAUNckT3_GUa8Ze2Eo,1511
|
|
11
|
+
RobotLog2RQM/RQM_templates/suiteexecutionrecord.xml,sha256=9GAs2WqZMkFJSNEZULm9BJvQy02dl_2JMecpQPHGTPA,1389
|
|
12
|
+
RobotLog2RQM/RQM_templates/testcase.xml,sha256=zovFKj-37QHn2S8mMA_9RnAJ3zBmDJkJj31yelsnFFI,2167
|
|
13
|
+
RobotLog2RQM/RQM_templates/testsuitelog.xml,sha256=l-NlaCyk6Ben76PElXKOHfMlEvyQ-e9MOZ6-F9HvwDQ,1920
|
|
14
|
+
robotframework_robotlog2rqm-1.2.4.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
15
|
+
robotframework_robotlog2rqm-1.2.4.dist-info/METADATA,sha256=l4Iqizjf3T408fSOv1EegnqPsXVhZ0z7vlu_fb05RpE,9332
|
|
16
|
+
robotframework_robotlog2rqm-1.2.4.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
17
|
+
robotframework_robotlog2rqm-1.2.4.dist-info/entry_points.txt,sha256=-Xug2kDJW2LtcSADEVPtCwa337twCy2iGh5aK7xApHA,73
|
|
18
|
+
robotframework_robotlog2rqm-1.2.4.dist-info/top_level.txt,sha256=jb_Gt6W44FoOLtGfBe7RzqCLaquhihkEWvSI1zjXDHc,13
|
|
19
|
+
robotframework_robotlog2rqm-1.2.4.dist-info/RECORD,,
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
RobotLog2RQM/CRQM.py,sha256=AeK_jh_oSrcgf7Io8iOl4UdPNWk20G8doh8PN2-aX0c,54873
|
|
2
|
-
RobotLog2RQM/RobotLog2RQM.pdf,sha256=o6aChhMjr3QCGcJ7AZ13leDnfVwUxcsOIImqIdI49l4,227725
|
|
3
|
-
RobotLog2RQM/__init__.py,sha256=Zv7Xsv-DqisEvX7CvIrIBq8K8lvA3ybQBwFFedUB4jY,611
|
|
4
|
-
RobotLog2RQM/__main__.py,sha256=aBgley3H6tcqzP5FxFxckuDuazXHSdzh9V2evliLNEc,695
|
|
5
|
-
RobotLog2RQM/robotlog2rqm.py,sha256=MFN0lTQGiNtWVv0pNoK6WsC84emI9bE45NEdZpGw3Mc,22868
|
|
6
|
-
RobotLog2RQM/version.py,sha256=QD0YG58zY3C1FnWxK8Y_PcG8SZBYjmkXRRqUBDTMf0A,917
|
|
7
|
-
RobotLog2RQM/RQM_templates/buildrecord.xml,sha256=uGot7pNOjPR8do0JsJi0Lz3OCU9NMhODRd428QgvHh4,1498
|
|
8
|
-
RobotLog2RQM/RQM_templates/configuration.xml,sha256=NrFDv51fuGhgeMiZuRhQ5q_UJ0u_pWzdxisIF5AJs74,1378
|
|
9
|
-
RobotLog2RQM/RQM_templates/executionresult.xml,sha256=WTp4qDk29peBc0ll6GHVXX_kF_YBsOVjy9vBzoz7_2k,2160
|
|
10
|
-
RobotLog2RQM/RQM_templates/executionworkitem.xml,sha256=3GYO-nvXcG-HDQZnDzGwYZSQOWAUNckT3_GUa8Ze2Eo,1511
|
|
11
|
-
RobotLog2RQM/RQM_templates/suiteexecutionrecord.xml,sha256=9GAs2WqZMkFJSNEZULm9BJvQy02dl_2JMecpQPHGTPA,1389
|
|
12
|
-
RobotLog2RQM/RQM_templates/testcase.xml,sha256=zovFKj-37QHn2S8mMA_9RnAJ3zBmDJkJj31yelsnFFI,2167
|
|
13
|
-
RobotLog2RQM/RQM_templates/testsuitelog.xml,sha256=l-NlaCyk6Ben76PElXKOHfMlEvyQ-e9MOZ6-F9HvwDQ,1920
|
|
14
|
-
robotframework_robotlog2rqm-1.2.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
15
|
-
robotframework_robotlog2rqm-1.2.1.dist-info/METADATA,sha256=GoswPQLB6ALEe1OZM27Y-Ba3jOlemU5Ic_jCISyQLaQ,9343
|
|
16
|
-
robotframework_robotlog2rqm-1.2.1.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
|
|
17
|
-
robotframework_robotlog2rqm-1.2.1.dist-info/entry_points.txt,sha256=-Xug2kDJW2LtcSADEVPtCwa337twCy2iGh5aK7xApHA,73
|
|
18
|
-
robotframework_robotlog2rqm-1.2.1.dist-info/top_level.txt,sha256=jb_Gt6W44FoOLtGfBe7RzqCLaquhihkEWvSI1zjXDHc,13
|
|
19
|
-
robotframework_robotlog2rqm-1.2.1.dist-info/RECORD,,
|
{robotframework_robotlog2rqm-1.2.1.dist-info → robotframework_robotlog2rqm-1.2.4.dist-info}/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|