From 72a74b282c234d330090668fbb9591c851ef6676 Mon Sep 17 00:00:00 2001 From: Michele Carignani Date: Thu, 18 Apr 2019 11:48:52 +0200 Subject: [PATCH 1/5] print cmds python3 compatible --- robot2doc/main.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/robot2doc/main.py b/robot2doc/main.py index aef2c0b..3e4402f 100644 --- a/robot2doc/main.py +++ b/robot2doc/main.py @@ -63,17 +63,17 @@ def gen_doc(src, doc_fn, doc_main_tit): try: workspace = TestSuiteBuilder().build(src) except: - print "Please check that first argument is a folder of Robot files or a single file." + print("Please check that first argument is a folder of Robot files or a single file.") exit(-1) - print "Loaded "+ str(len(workspace.suites)) + " test suites." + print("Loaded "+ str(len(workspace.suites)) + " test suites.") sec = DOC_CLAUSE_LVL_2 - 1 spec.add_main_heading(doc_main_tit) for suite in workspace.suites: sec = sec + 1 subsec = DOC_CLAUSE_LVL_4 - print " Generating test suite: " + str(suite) + print(" Generating test suite: " + str(suite)) spec.add_sub_heading(str(suite), DOC_CLAUSE_LVL_1, sec, DOC_CLAUSE_LVL_3, subsec) for i in suite.tests: print(" Generating test: " + str(i)) @@ -89,12 +89,12 @@ def gen_doc(src, doc_fn, doc_main_tit): print "Saving to: " + doc_fn spec.save(doc_fn) - print "Finished." + print("Finished.") if __name__ == "__main__": if len(sys.argv) < 2: - print "Usage: robot2doc [ [spec_section_title]]" + print("Usage: robot2doc [ [spec_section_title]]") FILE = sys.argv[1] DOC_FILENAME = sys.argv[2] if len(sys.argv) > 2 else DOC_FILENAME -- GitLab From d52e8a62318327706cf0991a629d616426840847 Mon Sep 17 00:00:00 2001 From: Michele Carignani Date: Tue, 7 May 2019 17:17:37 +0200 Subject: [PATCH 2/5] migrating to python3 --- examples/IndividualVNFPackage.robot | 68 ++++++++++++++ examples/ScaleVNFTask.robot | 135 ++++++++++++++++++++++++++++ examples/login.robot | 13 +++ robot2doc/__init__.py | 4 +- robot2doc/main.py | 1 + robot2doc/testspec.py | 4 +- tests/test_robot2doc.py | 6 ++ 7 files changed, 226 insertions(+), 5 deletions(-) create mode 100644 examples/IndividualVNFPackage.robot create mode 100644 examples/ScaleVNFTask.robot create mode 100644 examples/login.robot create mode 100644 tests/test_robot2doc.py diff --git a/examples/IndividualVNFPackage.robot b/examples/IndividualVNFPackage.robot new file mode 100644 index 0000000..4304923 --- /dev/null +++ b/examples/IndividualVNFPackage.robot @@ -0,0 +1,68 @@ +*** Settings *** +Library JSONSchemaLibrary schemas/ +Resource environment/generic.txt # Generic Parameters +Resource environment/individualVnfPackage.txt +Library JSONLibrary +Library REST ${NFVO_SCHEMA}://${NFVO_HOST}:${NFVO_PORT} + +*** Test Cases *** +GET Individual VNF Package + Log Trying to get a VNF Package present in the NFVO Catalogue + Set Headers {"Accept": "${ACCEPT_JSON}"} + Run Keyword If ${AUTH_USAGE} == 1 Set Headers {"Authorization": "${AUTHORIZATION}"} + GET ${apiRoot}/${apiName}/${apiVersion}/vnf_packages/${vnfPackageId} + Integer response status 200 + ${contentType}= Output response headers Content-Type + Should Contain ${contentType} ${CONTENT_TYPE_JSON} + Log Trying to validate response + ${vnfPkgInfo}= Output response body + ${json}= evaluate json.loads('''${vnfPkgInfo}''') json + Validate Json vnfPkgInfo.schema.json ${json} + Log Validation OK + +GET Individual VNF Package - Negative (Not Found) + Log Trying to perform a negative get, using wrong authorization bearer + Set Headers {"Accept": "${ACCEPT_JSON}"} + Run Keyword If ${AUTH_USAGE} == 1 Set Headers {"Authorization": "${AUTHORIZATION}"} + GET ${apiRoot}/${apiName}/${apiVersion}/vnf_packages/${erroneousVnfPackageId} + Integer response status 404 + Log Received 404 Not Found as expected + ${contentType}= Output response headers Content-Type + Should Contain ${contentType} ${CONTENT_TYPE_JSON} + Log Trying to validate ProblemDetails + ${problemDetails}= Output response body + ${json}= evaluate json.loads('''${problemDetails}''') json + Validate Json ProblemDetails.schema.json ${json} + Log Validation OK + +POST Individual VNF Package - (Method not implemented) + Log Trying to perform a POST (method should not be implemented) + Set Headers {"Accept": "${ACCEPT_JSON}"} + Run Keyword If ${AUTH_USAGE} == 1 Set Headers {"Authorization": "${AUTHORIZATION}"} + POST ${apiRoot}/${apiName}/${apiVersion}/vnf_packages/${vnfPackageId} + Integer response status 405 + Log Received 405 Method not implemented as expected + +PUT Individual VNF Package - (Method not implemented) + Log Trying to perform a PUT. This method should not be implemented + Set Headers {"Accept": "${ACCEPT_JSON}"} + Run Keyword If ${AUTH_USAGE} == 1 Set Headers {"Authorization": "${AUTHORIZATION}"} + PUT ${apiRoot}/${apiName}/${apiVersion}/vnf_packages/${vnfPackageId} + Integer response status 405 + Log Received 405 Method not implemented as expected + +PATCH Individual VNF Package - (Method not implemented) + Log Trying to perform a PATCH. This method should not be implemented + Set Headers {"Accept": "${ACCEPT_JSON}"} + Run Keyword If ${AUTH_USAGE} == 1 Set Headers {"Authorization": "${AUTHORIZATION}"} + PATCH ${apiRoot}/${apiName}/${apiVersion}/vnf_packages/${vnfPackageId} + Integer response status 405 + Log Received 405 Method not implemented as expected + +DELETE Individual VNF Package - (Method not implemented) + Log Trying to perform a DELETE. This method should not be implemented + Set Headers {"Accept": "${ACCEPT_JSON}"} + Run Keyword If ${AUTH_USAGE} == 1 Set Headers {"Authorization": "${AUTHORIZATION}"} + DELETE ${apiRoot}/${apiName}/${apiVersion}/vnf_packages/${vnfPackageId} + Integer response status 405 + Log Received 405 Method not implemented as expected diff --git a/examples/ScaleVNFTask.robot b/examples/ScaleVNFTask.robot new file mode 100644 index 0000000..c6de93b --- /dev/null +++ b/examples/ScaleVNFTask.robot @@ -0,0 +1,135 @@ +*** Settings *** +# Resource variables.txt +#Library REST http://${VNFM_HOST}:${VNFM_PORT} +# ... spec=SOL003-VNFLifecycleManagement-API.yaml +#Library DependencyLibrary +#Library OperatingSystem + +*** Test Cases *** +Scale a vnfInstance + [Documentation] Test Name: Scale VNF The POST method scales a VNF instance.. + ... Another: The operation cannot be executed currently, due to a conflict with the state of the VNF instance resource. + ... Applicability: Typically, this is due to the fact that the VNF instance resource is in NOT-INSTANTIATED state, or that another lifecycle management operation is ongoing. + ... Post-conditions: The response body shall contain a ProblemDetails structure, in which the detail attribute should convey more information about the error. + Log Trying to scale a vnf Instance + Set Headers {"Accept":"${ACCEPT}"} + Set Headers {"Content-Type": "${CONTENT_TYPE}"} + Run Keyword If ${AUTH_USAGE} == 1 Set Headers {"Authorization":"${AUTHORIZATION}"} + ${body}= Get File json/scaleVnfRequest.json + Post ${apiRoot}/${apiName}/${apiVersion}/vnf_instances/${vnfInstanceId}/scale ${body} + Integer response status 202 + Log Status code validated + +Scale a vnfInstance Conflict (Not-Instantiated) + # TODO: Need to set the pre-condition of the test. VNF instance shall be in NOT-INSTANTIATED state + [Documentation] Prova: Conflict. + ... Another: The operation cannot be executed currently, due to a conflict with the state of the VNF instance resource. + ... Applicability: Typically, this is due to the fact that the VNF instance resource is in NOT-INSTANTIATED state, or that another lifecycle management operation is ongoing. + ... The response body shall contain a ProblemDetails structure, in which the detail attribute should convey more information about the error. + [Setup] Check resource not instantiated + Log Trying to Scale a vnf Instance + Set Headers {"Accept":"${ACCEPT}"} + Set Headers {"Content-Type": "${CONTENT_TYPE}"} + Run Keyword If ${AUTH_USAGE} == 1 Set Headers {"Authorization":"${AUTHORIZATION}"} + ${body}= Get File json/scaleVnfRequest.json + Post ${apiRoot}/${apiName}/${apiVersion}/vnf_instances/${vnfInstanceId}/scale ${body} + Output response + Integer response status 409 + Log Status code validated + +Scale a vnfInstance Conflict (parallel LCM operation) + # TODO: Need to set the pre-condition of the test + [Documentation] Example: Conflict + ... Maybe: The operation cannot be executed currently, due to a conflict with the state of the VNF instance resource. + ... Typically, this is due to the fact that the VNF instance resource is in NOT-INSTANTIATED state, or that another lifecycle management operation is ongoing. + ... The response body shall contain a ProblemDetails structure, in which the detail attribute should convey more information about the error. + [Setup] Launch another LCM operation + log Trying to Scale a vnf Instance + Set Headers {"Accept":"${ACCEPT}"} + Set Headers {"Content-Type": "${CONTENT_TYPE}"} + Run Keyword If ${AUTH_USAGE} == 1 Set Headers {"Authorization":"${AUTHORIZATION}"} + ${body}= Get File json/scaleVnfRequest.json + Post ${apiRoot}/${apiName}/${apiVersion}/vnf_instances/${vnfInstanceId}/scale ${body} + Log Validate Status code + Output response + Integer response status 409 + [Teardown] #We cannot know if the "scale" operation is finished easily because the 202 indicates only whether the operation has been accepted, not whether the operation has been finished + +Scale a vnfInstance Not Found + # TODO: Need to create a vnfInstance which's instantiatedVnfInfo.scaleStatus is absent + [Documentation] Not Found + ... Error: The API producer did not find a current representation for the target resource or is not willing to disclose that one exists. + ... Specifically in case of this task resource, the response code 404 shall also returned if the task is not supported for the VNF instance represented by the parent resource, which means that the task resource consequently does not exist. + ... In this case, the response body shall be present, and shall contain a ProblemDetails structure, in which the detail attribute shall convey more information about the error. + [Setup] Check scale not supported + Log Trying to scale a vnf Instance, not exist + Set Headers {"Accept":"${ACCEPT}"} + Set Headers {"Content-Type": "${CONTENT_TYPE}"} + Run Keyword If ${AUTH_USAGE} == 1 Set Headers {"Authorization":"${AUTHORIZATION}"} + ${body}= Get File json/scaleVnfRequest.json + Post ${apiRoot}/${apiName}/${apiVersion}/vnf_instances/${vnfInstanceId}/scale ${body} + Integer response status 404 + Log Status code validated + + +GET Scale VNFInstance - Method not implemented + log Trying to perform a GET. This method should not be implemented + Run Keyword If ${AUTH_USAGE} == 1 Set Headers {"Authorization":"${AUTHORIZATION}"} + Get ${apiRoot}/${apiName}/${apiVersion}/vnf_instances/${vnfInstanceId}/scale + Log Validate Status code + Output response + Integer response status 405 + +PUT Scale VNFInstance - Method not implemented + log Trying to perform a PUT. This method should not be implemented + Run Keyword If ${AUTH_USAGE} == 1 Set Headers {"Authorization":"${AUTHORIZATION}"} + Put ${apiRoot}/${apiName}/${apiVersion}/vnf_instances/${vnfInstanceId}/scale + Log Validate Status code + Output response + Integer response status 405 + +PATCH Scale VNFInstance - Method not implemented + log Trying to perform a PATCH. This method should not be implemented + Run Keyword If ${AUTH_USAGE} == 1 Set Headers {"Authorization":"${AUTHORIZATION}"} + Patch ${apiRoot}/${apiName}/${apiVersion}/vnf_instances/${vnfInstanceId}/scale + Log Validate Status code + Output response + Integer response status 405 + +DELETE Scale VNFInstance - Method not implemented + log Trying to perform a DELETE. This method should not be implemented + Run Keyword If ${AUTH_USAGE} == 1 Set Headers {"Authorization":"${AUTHORIZATION}"} + Delete ${apiRoot}/${apiName}/${apiVersion}/vnf_instances/${vnfInstanceId}/scale + Log Validate Status code + Output response + Integer response status 405 + +*** Key words *** +Check resource existance + Set Headers {"Accept":"${ACCEPT}"} + Set Headers {"Content-Type": "${CONTENT_TYPE}"} + Run Keyword If ${AUTH_USAGE} == 1 Set Headers {"Authorization":"${AUTHORIZATION}"} + Get ${apiRoot}/${apiName}/${apiVersion}/vnf_instances/${vnfInstanceId} + Integer response status 200 + +Check resource not instantiated + Set Headers {"Accept":"${ACCEPT}"} + Set Headers {"Content-Type": "${CONTENT_TYPE}"} + Run Keyword If ${AUTH_USAGE} == 1 Set Headers {"Authorization":"${AUTHORIZATION}"} + Get ${apiRoot}/${apiName}/${apiVersion}/vnf_instances/${vnfInstanceId} + String response body instantiationState NOT_INSTANTIATED + +Check scale not supported + Set Headers {"Accept":"${ACCEPT}"} + Set Headers {"Content-Type": "${CONTENT_TYPE}"} + Run Keyword If ${AUTH_USAGE} == 1 Set Headers {"Authorization":"${AUTHORIZATION}"} + Get ${apiRoot}/${apiName}/${apiVersion}/vnf_instances/${vnfInstanceId} + Missing response body instantiatedVnfInfo scaleStatus + +Launch another LCM operation + Set Headers {"Accept":"${ACCEPT}"} + Set Headers {"Content-Type": "${CONTENT_TYPE}"} + Run Keyword If ${AUTH_USAGE} == 1 Set Headers {"Authorization":"${AUTHORIZATION}"} + ${body}= Get File json/scaleVnfToLevelRequest.json + Post ${apiRoot}/${apiName}/${apiVersion}/vnf_instances/${vnfInstanceId}/scale_to_level ${body} + Integer response status 202 \ No newline at end of file diff --git a/examples/login.robot b/examples/login.robot new file mode 100644 index 0000000..74409e4 --- /dev/null +++ b/examples/login.robot @@ -0,0 +1,13 @@ +*** Settings *** +Documentation A test suite with a single test for valid login. +... +... This test has a workflow that is created using keywords in +... the imported resource file. + +*** Test Cases *** +Valid Login + Open Browser To Login Page + Input Username demo + Input Password mode + Submit Credentials + Welcome Page Should Be Open diff --git a/robot2doc/__init__.py b/robot2doc/__init__.py index dffd541..ca23dc0 100644 --- a/robot2doc/__init__.py +++ b/robot2doc/__init__.py @@ -1,3 +1 @@ -name = "robot2doc" - -from main import gen_doc +name = "robot2doc" \ No newline at end of file diff --git a/robot2doc/main.py b/robot2doc/main.py index 3e4402f..1371990 100644 --- a/robot2doc/main.py +++ b/robot2doc/main.py @@ -60,6 +60,7 @@ def gen_doc(src, doc_fn, doc_main_tit): finally: os.chdir(cwd) + print("Loading tests from: " + src) try: workspace = TestSuiteBuilder().build(src) except: diff --git a/robot2doc/testspec.py b/robot2doc/testspec.py index 8f902a1..1368ef7 100644 --- a/robot2doc/testspec.py +++ b/robot2doc/testspec.py @@ -26,8 +26,8 @@ class TestSpec(): def __init__(self, path=None): if path: - print("opening doc: "+path) - print("current dir: "+os.getcwd()) + print("Opening doc: "+path) + print("Current dir: "+os.getcwd()) self.doc = Document(path) @staticmethod diff --git a/tests/test_robot2doc.py b/tests/test_robot2doc.py new file mode 100644 index 0000000..430f2a5 --- /dev/null +++ b/tests/test_robot2doc.py @@ -0,0 +1,6 @@ +#!/env/python + +import robot2doc + +def test_keyword_to_line(): + assert keyword_to_line("a", "b", "c") == "a b c" \ No newline at end of file -- GitLab From ab5650172fa451cd6ab058c4a45344d2ed2aec2c Mon Sep 17 00:00:00 2001 From: Michele Carignani Date: Tue, 2 Jul 2019 10:03:48 +0200 Subject: [PATCH 3/5] better logging, git commit url after tables --- robot2doc/config.py | 12 ++++++++++ robot2doc/main.py | 47 +++++++++++++++++++++++++--------------- robot2doc/testpurpose.py | 10 ++++++--- robot2doc/testspec.py | 3 +++ 4 files changed, 52 insertions(+), 20 deletions(-) diff --git a/robot2doc/config.py b/robot2doc/config.py index ed6ee5f..369317c 100644 --- a/robot2doc/config.py +++ b/robot2doc/config.py @@ -18,3 +18,15 @@ DOC_MAIN_TITLE = '9 Test Cases' DOC_FILENAME = 'test_spec_from_robot.docx' FILE = "" BASE_SPEC = 'basespec.docx' + +# If DRY_RUN is True, no output file is created +DRY_RUN = False + +# If QUIET is True, output on stdout is minimized +QUIET = False + +# Commit URL that may be added after each table. If the GIT_COMMIT +# is the empty string, nothing is added +# Example: +# GIT_COMMIT = "http://acme.com/my/example/abcde" +GIT_COMMIT = "" \ No newline at end of file diff --git a/robot2doc/main.py b/robot2doc/main.py index 1371990..a7e886a 100644 --- a/robot2doc/main.py +++ b/robot2doc/main.py @@ -23,6 +23,9 @@ DOC_FILENAME = cfg.DOC_FILENAME FILE = cfg.DOC_FILENAME BASE_SPEC = cfg.BASE_SPEC +DRY_RUN = cfg.DRY_RUN +QUIET = cfg.QUIET + def keyword_to_line(k): ''' Takes a Robot Framework keyword object and returns @@ -36,6 +39,23 @@ def keywords_to_text(kws): ''' return "\n".join(map(keyword_to_line, kws)) +def gen_test(suite, this_test, spec, sec, subsec, workspace): + global DRY_RUN + + tp = TP(this_test.doc) + + log_line = ["TD", str(workspace), str(suite), str(this_test), tp.tp_id or "No ID" ] + not QUIET and print(",".join(log_line)) + + if DRY_RUN: + return + if tp.tp_id != None: + spec.add_heading(str(this_test), DOC_TC_LEVEL, tp.tp_id) + else: + subsec = subsec + 1 + spec.add_heading(str(this_test), DOC_TC_LEVEL, DOC_CLAUSE_LVL_1, sec, DOC_CLAUSE_LVL_3, subsec) + tp.add_to_spec(spec, keywords_to_text(this_test.keywords)) + def gen_doc(src, doc_fn, doc_main_tit): ''' Converts a Robot test suite to a word document @@ -47,8 +67,8 @@ def gen_doc(src, doc_fn, doc_main_tit): doc_main_tit top level title for the section in the doc ''' - print("### robot2doc version " + cfg.VERSION) - print "Starting.." + not QUIET and print("### robot2doc version " + cfg.VERSION) + not QUIET and print("Starting..") script_dir = os.path.dirname(os.path.realpath(__file__)) cwd = os.getcwd() @@ -67,35 +87,28 @@ def gen_doc(src, doc_fn, doc_main_tit): print("Please check that first argument is a folder of Robot files or a single file.") exit(-1) - print("Loaded "+ str(len(workspace.suites)) + " test suites.") + not QUIET and print("Loaded "+ str(len(workspace.suites)) + " test suites.") sec = DOC_CLAUSE_LVL_2 - 1 spec.add_main_heading(doc_main_tit) + for suite in workspace.suites: sec = sec + 1 subsec = DOC_CLAUSE_LVL_4 print(" Generating test suite: " + str(suite)) spec.add_sub_heading(str(suite), DOC_CLAUSE_LVL_1, sec, DOC_CLAUSE_LVL_3, subsec) for i in suite.tests: - print(" Generating test: " + str(i)) - tp = TP(i.doc) - if tp.tp_id != None: - spec.add_heading(str(i), DOC_TC_LEVEL, tp.tp_id) - print(" Has TP ID: " + tp.tp_id) - else: - subsec = subsec + 1 - print(" Has NO TP ID.") - spec.add_heading(str(i), DOC_TC_LEVEL, DOC_CLAUSE_LVL_1, sec, DOC_CLAUSE_LVL_3, subsec) - tp.add_to_spec(spec, keywords_to_text(i.keywords)) - - print "Saving to: " + doc_fn - spec.save(doc_fn) - print("Finished.") + gen_test(suite, i, spec, sec, subsec, workspace) + + not QUIET and print("Saving to: " + doc_fn) + not DRY_RUN and spec.save(doc_fn) + not QUIET and print("Finished.") if __name__ == "__main__": if len(sys.argv) < 2: print("Usage: robot2doc [ [spec_section_title]]") + exit(-1) FILE = sys.argv[1] DOC_FILENAME = sys.argv[2] if len(sys.argv) > 2 else DOC_FILENAME diff --git a/robot2doc/testpurpose.py b/robot2doc/testpurpose.py index deeeb9d..3513610 100644 --- a/robot2doc/testpurpose.py +++ b/robot2doc/testpurpose.py @@ -1,5 +1,7 @@ #!/env/python +import config + class TpField(): ''' Describe a field in a Test Purpose, via its key and value @@ -19,8 +21,8 @@ class TP(): with key value pairs, each separated by ":". ''' def __init__(self, text): - t = text.encode('ascii') - self.lines = t.split("\\n") + # t = text.encode('ascii') + self.lines = text.split("\\n") self.tp_fields = map(TpField, self.lines) self.tp_id = None @@ -32,4 +34,6 @@ class TP(): return str(self.lines) def add_to_spec(self, spec, test): - spec.add_tp(self.tp_fields, test) \ No newline at end of file + spec.add_tp(self.tp_fields, test) + if config.GIT_COMMIT != "": + spec.add_commit_url(config.GIT_COMMIT) \ No newline at end of file diff --git a/robot2doc/testspec.py b/robot2doc/testspec.py index 1368ef7..3e383db 100644 --- a/robot2doc/testspec.py +++ b/robot2doc/testspec.py @@ -68,6 +68,9 @@ class TestSpec(): TestSpec.cell_text_bold(hdr_cells[0]) TestSpec.cell_text_centered(hdr_cells[0]) + def add_commit_url(self, commit): + self.doc.add_paragraph("Note: Robot code can be found at " + commit) + def add_tp(self, fields, testbehaviour): table = self.doc.add_table(cols=2, rows=1) table.style = TABLE_STYLE -- GitLab From e724f267342beda6cb17034fc5f2d98776dbc812 Mon Sep 17 00:00:00 2001 From: Michele Carignani Date: Thu, 4 Jul 2019 19:04:28 +0200 Subject: [PATCH 4/5] Fixes TP headers, URL is a prefix + filename --- examples/VNFPackageArtifacts.robot | 147 +++++++++++++++++++++++++++++ robot2doc/config.py | 9 +- robot2doc/main.py | 11 ++- robot2doc/testpurpose.py | 16 ++-- robot2doc/testspec.py | 8 +- 5 files changed, 178 insertions(+), 13 deletions(-) create mode 100644 examples/VNFPackageArtifacts.robot diff --git a/examples/VNFPackageArtifacts.robot b/examples/VNFPackageArtifacts.robot new file mode 100644 index 0000000..27c636f --- /dev/null +++ b/examples/VNFPackageArtifacts.robot @@ -0,0 +1,147 @@ +*** Settings *** +Library JSONSchemaLibrary schemas/ +Resource environment/variables.txt # Generic Parameters +Resource environment/vnfPackageArtifacts.txt +Resource VNFPackageManagementKeywords.robot +Library JSONLibrary +Library REST ${NFVO_SCHEMA}://${NFVO_HOST}:${NFVO_PORT} + +*** Test Cases *** +GET Individual VNF Package Artifact + [Documentation] Test ID: 7.3.3.5.1 + ... Test title: GET Individual VNF Package Artifact + ... Test objective: The objective is to test the retrieval of an individual VNF package artifact + ... Pre-conditions: One or more VNF packages are onboarded in the NFVO. + ... Reference: section 10.4.6.3.2 - SOL003 v2.4.1 + ... Config ID: Config_prod_NFVO + ... Applicability: none + ... Post-Conditions: none + GET Individual VNF Package Artifact + Check HTTP Response Status Code Is 200 + + +GET Individual VNF Package Artifact in octet stream format + [Documentation] Test ID: 7.3.3.5.2 + ... Test title: GET Individual VNF Package Artifact in octet stream format + ... Test objective: The objective is to test the retrieval of an individual VNF package artifact when the NFVO cannot determine the artifact content type. The test performs a validation that the returned artifcat in is octet-stream format + ... Pre-conditions: One or more VNF packages are onboarded in the NFVO. + ... Reference: section 10.4.6.3.2 - SOL003 v2.4.1 + ... Config ID: Config_prod_NFVO + ... Applicability: The NFVO cannot determine the content type of the artifact + ... Post-Conditions: none + GET Individual VNF Package Artifact in octet stream format + Check HTTP Response Status Code Is 200 + Check HTTP Response Header Content-Type Is application/octet-stream + +GET Individual VNF Package Artifact with Range Request and NFVO supporting Range Requests + [Documentation] Test ID: 7.3.3.5.3 + ... Test title: GET Individual VNF Package Artifact with Range Request and NFVO supporting Range Requests + ... Test objective: The objective is to test the retrieval of an individual VNF package artifact when using a range request to return single range of bytes from the file, with the NFVO supporting it. The test also perform a validation that returned content matches the issued range + ... Pre-conditions: One or more VNF packages are onboarded in the NFVO. + ... Reference: section 10.4.6.3.2 - SOL003 v2.4.1 + ... Config ID: Config_prod_NFVO + ... Applicability: The NFVO supports range requests to return single range of bytes from the VNF package artifact + ... Post-Conditions: none + GET Individual VNF Package Artifact with Range Request + Check HTTP Response Status Code Is 206 + Check HTTP Response Header Content-Range Is Present and Matches the requested range + Check HTTP Response Header Content-Length Is Present and Matches the requested range length + +GET Individual VNF Package Artifact with Range Request and NFVO not supporting Range Requests + [Documentation] Test ID: 7.3.3.5.4 + ... Test title: GET Individual VNF Package Artifact with Range Request and NFVO not supporting Range Requests + ... Test objective: The objective is to test that the retrieval of an individual VNF package artifact, when using a range request to return single range of bytes from the file and the NFVO not supporting it, returns the full VNF Package artifact. + ... Pre-conditions: One or more VNF packages are onboarded in the NFVO. + ... Reference: section 10.4.6.3.2 - SOL003 v2.4.1 + ... Config ID: Config_prod_NFVO + ... Applicability: The NFVO does not support range requests to return single range of bytes from the VNF package artifact + ... Post-Conditions: none + GET Individual VNF Package Artifact with Range Request + Check HTTP Response Status Code Is 200 + +GET Individual VNF Package Artifact with invalid Range Request + [Documentation] Test ID: 7.3.3.5.5 + ... Test title: GET Individual VNF Package Artifact with invalid Range Request + ... Test objective: The objective is to test that the retrieval of an individual VNF package artifact fails when using a range request that does not match any available byte range in the file. + ... Pre-conditions: One or more VNF packages are onboarded in the NFVO. + ... Reference: section 10.4.6.3.2 - SOL003 v2.4.1 + ... Config ID: Config_prod_NFVO + ... Applicability: The NFVO supports range requests to return single range of bytes from the VNF package artifact + ... Post-Conditions: none + GET Individual VNF Package Artifact with invalid Range Request + Check HTTP Response Status Code Is 416 + +GET Individual VNF Package Artifact with invalid resource identifier + [Documentation] Test ID: 7.3.3.5.6 + ... Test title: GET Individual VNF Package Artifact with invalid resource identifier + ... Test objective: The objective is to test that the retrieval of an individual VNF package artifact fails when using an invalid resource identifier + ... Pre-conditions: One or more VNF packages are onboarded in the NFVO. + ... Reference: section 10.4.6.3.2 - SOL003 v2.4.1 + ... Config ID: Config_prod_NFVO + ... Applicability: none + ... Post-Conditions: none + GET Individual VNF Package Artifact with invalid resource identifier + Check HTTP Response Status Code Is 404 + +GET Individual VNF Package Artifact with conflict due to onboarding state + [Documentation] Test ID: 7.3.3.5.7 + ... Test title: GET Individual VNF Package Artifact with conflict due to onboarding state + ... Test objective: The objective is to test that the retrieval of an individual VNF package artifact fails due to a conflict when the VNF Package is not in onboarding state ONBOARDED in the NFVO. The test also performs a validation of the JSON schema validation of the failed operation HTTP response + ... Pre-conditions: The onboarding state of the VNF package for which the content is requested is different from ONBOARDED. + ... Reference: section 10.4.6.3.2 - SOL003 v2.4.1 + ... Config ID: Config_prod_NFVO + ... Applicability: none + ... Post-Conditions: none + GET Artifact for VNF Package in onboarding state different from ONBOARDED + Check HTTP Response Status Code Is 409 + Check HTTP Response Body Json Schema Is ProblemDetails + +POST Individual VNF Package Artifact - Method not implemented + [Documentation] Test ID: 7.3.3.5.8 + ... Test title: POST Individual VNF Package Artifact - Method not implemented + ... Test objective: The objective is to test that POST method is not allowed to create new VNF Package artifact + ... Pre-conditions: none + ... Reference: section 10.4.6.3.1 - SOL003 v2.4.1 + ... Config ID: Config_prod_NFVO + ... Applicability: none + ... Post-Conditions: none + Send POST Request for individual VNF Package Artifact + Check HTTP Response Status Code Is 405 + +PUT Individual VNF Package Artifact - Method not implemented + [Documentation] Test ID: 7.3.3.5.9 + ... Test title: PUT Individual VNF Package Artifact - Method not implemented + ... Test objective: The objective is to test that PUT method is not allowed to modify a VNF Package artifact + ... Pre-conditions: One or more VNF packages are onboarded in the NFVO. + ... Reference: section 10.4.6.3.3 - SOL003 v2.4.1 + ... Config ID: Config_prod_NFVO + ... Applicability: none + ... Post-Conditions: none + Send PUT Request for individual VNF Package Artifact + Check HTTP Response Status Code Is 405 + +PATCH Individual VNF Package Artifact - Method not implemented + [Documentation] Test ID: 7.3.3.5.10 + ... Test title: PATCH Individual VNF Package Artifact - Method not implemented + ... Test objective: The objective is to test that PATCH method is not allowed to update a VNF Package artifact + ... Pre-conditions: One or more VNF packages are onboarded in the NFVO. + ... Reference: section 10.4.6.3.4 - SOL003 v2.4.1 + ... Config ID: Config_prod_NFVO + ... Applicability: none + ... Post-Conditions: none + Send PATCH Request for individual VNF Package Artifact + Check HTTP Response Status Code Is 405 + +DELETE Individual VNF Package Artifact - Method not implemented + [Documentation] Test ID: 7.3.3.5.11 + ... Test title: DELETE Individual VNF Package Artifact - Method not implemented + ... Test objective: The objective is to test that DELETE method is not allowed to delete a VNF Package artifact + ... Pre-conditions: One or more VNF packages are onboarded in the NFVO. + ... Reference: section 10.4.6.3.5 - SOL003 v2.4.1 + ... Config ID: Config_prod_NFVO + ... Applicability: none + ... Post-Conditions: The VNF Package artifact is not deleted by the failed operation + Send DELETE Request for individual VNF Package Artifact + Check HTTP Response Status Code Is 405 + Check Postcondition VNF Package Artifact Exist + diff --git a/robot2doc/config.py b/robot2doc/config.py index 369317c..566fd87 100644 --- a/robot2doc/config.py +++ b/robot2doc/config.py @@ -25,8 +25,9 @@ DRY_RUN = False # If QUIET is True, output on stdout is minimized QUIET = False -# Commit URL that may be added after each table. If the GIT_COMMIT -# is the empty string, nothing is added +# Prefix for the commit URL that may be added after each table. If the GIT_COMMIT +# is the empty string, nothing is added. The prefix is concatenated with the filename of +# the Robot file. NOTE: if the final slash is not present it will not be included. # Example: -# GIT_COMMIT = "http://acme.com/my/example/abcde" -GIT_COMMIT = "" \ No newline at end of file +# GIT_COMMIT = "http://acme.com/my/example/abcde/" +GIT_COMMIT_PREFIX = "https://forge.etsi.org/gitlab/nfv/api-tests/raw/XX-commit-XX/SOL00Y/AAA-API/" \ No newline at end of file diff --git a/robot2doc/main.py b/robot2doc/main.py index a7e886a..d7ae58c 100644 --- a/robot2doc/main.py +++ b/robot2doc/main.py @@ -54,7 +54,7 @@ def gen_test(suite, this_test, spec, sec, subsec, workspace): else: subsec = subsec + 1 spec.add_heading(str(this_test), DOC_TC_LEVEL, DOC_CLAUSE_LVL_1, sec, DOC_CLAUSE_LVL_3, subsec) - tp.add_to_spec(spec, keywords_to_text(this_test.keywords)) + tp.add_to_spec(spec, keywords_to_text(this_test.keywords), str(suite)+".robot") def gen_doc(src, doc_fn, doc_main_tit): ''' @@ -88,6 +88,7 @@ def gen_doc(src, doc_fn, doc_main_tit): exit(-1) not QUIET and print("Loaded "+ str(len(workspace.suites)) + " test suites.") + not QUIET and print("Loaded "+ str(len(workspace.tests)) + " tests.") sec = DOC_CLAUSE_LVL_2 - 1 spec.add_main_heading(doc_main_tit) @@ -99,6 +100,14 @@ def gen_doc(src, doc_fn, doc_main_tit): spec.add_sub_heading(str(suite), DOC_CLAUSE_LVL_1, sec, DOC_CLAUSE_LVL_3, subsec) for i in suite.tests: gen_test(suite, i, spec, sec, subsec, workspace) + + if len(workspace.suites) == 0: + sec = sec + 1 + subsec = DOC_CLAUSE_LVL_4 + suite = str(workspace) + spec.add_sub_heading(suite, DOC_CLAUSE_LVL_1, sec, DOC_CLAUSE_LVL_3, subsec) + for i in workspace.tests: + gen_test(suite, i, spec, sec, subsec, workspace) not QUIET and print("Saving to: " + doc_fn) not DRY_RUN and spec.save(doc_fn) diff --git a/robot2doc/testpurpose.py b/robot2doc/testpurpose.py index 3513610..94b71d8 100644 --- a/robot2doc/testpurpose.py +++ b/robot2doc/testpurpose.py @@ -1,6 +1,7 @@ #!/env/python import config +import testspec class TpField(): ''' @@ -20,10 +21,10 @@ class TP(): Defines a test purpose. The constructor parses a set of lines with key value pairs, each separated by ":". ''' - def __init__(self, text): + def __init__(self, text : str): # t = text.encode('ascii') self.lines = text.split("\\n") - self.tp_fields = map(TpField, self.lines) + self.tp_fields = [TpField(l) for l in self.lines] self.tp_id = None for field in self.tp_fields: @@ -33,7 +34,10 @@ class TP(): def __str__(self): return str(self.lines) - def add_to_spec(self, spec, test): - spec.add_tp(self.tp_fields, test) - if config.GIT_COMMIT != "": - spec.add_commit_url(config.GIT_COMMIT) \ No newline at end of file + def add_to_spec(self, spec : testspec.TestSpec, testbehaviour: str, robot_file : str): + ''' + Given a Test Spec, executes the addition of the this TP in the document. + ''' + spec.add_tp(self.tp_fields, testbehaviour) + if config.GIT_COMMIT_PREFIX != "": + spec.add_commit_url(config.GIT_COMMIT_PREFIX, robot_file) \ No newline at end of file diff --git a/robot2doc/testspec.py b/robot2doc/testspec.py index 3e383db..fe36898 100644 --- a/robot2doc/testspec.py +++ b/robot2doc/testspec.py @@ -68,8 +68,12 @@ class TestSpec(): TestSpec.cell_text_bold(hdr_cells[0]) TestSpec.cell_text_centered(hdr_cells[0]) - def add_commit_url(self, commit): - self.doc.add_paragraph("Note: Robot code can be found at " + commit) + def add_commit_url(self, commit : str, robot_file : str): + ''' + Adds a note to the document containing the URL to the location of the + file, according to the configured URL prefix configured. + ''' + self.doc.add_paragraph("Note: Robot code can be found at " + commit + robot_file) def add_tp(self, fields, testbehaviour): table = self.doc.add_table(cols=2, rows=1) -- GitLab From f0258644d73b8f2b5e7757c560b2abee3930e45a Mon Sep 17 00:00:00 2001 From: Michele Carignani Date: Fri, 5 Jul 2019 10:00:13 +0200 Subject: [PATCH 5/5] improved documentation and testing --- Readme.md | 3 +++ robot2doc/main.py | 3 +++ tests/test_robot2doc.py | 6 ------ 3 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 tests/test_robot2doc.py diff --git a/Readme.md b/Readme.md index 22912a4..098be97 100644 --- a/Readme.md +++ b/Readme.md @@ -21,6 +21,9 @@ Command line arguments: Other configurable paramenters may be found in `config.py`, such as: * ` DOC_CLAUSE_LVL_*`, the starting number for the sections numbering, with `LVL_1` being the number of the toplevel clause. +* `DRY_RUN`, if True, no output Docx file is created +* `QUIET`, if True, output on stdout is minimized +* `GIT_COMMIT_PREFIX`, If not empty, a NOTE is added after each test with this URL concatenated to the name of the Robot file(s) in input ## How to write the tests diff --git a/robot2doc/main.py b/robot2doc/main.py index d7ae58c..cc62c19 100644 --- a/robot2doc/main.py +++ b/robot2doc/main.py @@ -40,6 +40,9 @@ def keywords_to_text(kws): return "\n".join(map(keyword_to_line, kws)) def gen_test(suite, this_test, spec, sec, subsec, workspace): + ''' + Generate the Docx part for an individual test + ''' global DRY_RUN tp = TP(this_test.doc) diff --git a/tests/test_robot2doc.py b/tests/test_robot2doc.py deleted file mode 100644 index 430f2a5..0000000 --- a/tests/test_robot2doc.py +++ /dev/null @@ -1,6 +0,0 @@ -#!/env/python - -import robot2doc - -def test_keyword_to_line(): - assert keyword_to_line("a", "b", "c") == "a b c" \ No newline at end of file -- GitLab