diff options
87 files changed, 4729 insertions, 478 deletions
diff --git a/INFO.yaml b/INFO.yaml new file mode 100644 index 0000000..c283eca --- /dev/null +++ b/INFO.yaml @@ -0,0 +1,47 @@ +--- +subproject: 'Test Results Collecting and Analyzing (TestResults)' +project_category: 'Integration & Testing' +lifecycle_state: 'Incubation' +subproject_lead: &opnfv_testresults_ptl + name: 'SerenaFeng' + email: 'feng.xiaowei@zte.com.cn' + id: 'serenafeng' + company: 'ZTE' + timezone: 'China' +primary_contact: *opnfv_testresults_ptl +issue_tracking: + type: 'jira' + url: 'https://jira.opnfv.org/projects/RELENG' + key: 'RELENG' +mailing_list: + type: 'mailman2' + url: 'opnfv-tech-discuss@lists.opnfv.org' + tag: '[testresults]' +meetings: + - type: 'appearin' + url: 'https://appear.in/serenafeng' + repeats: 'weekly' + day: 'Thursday' + time: '13:30 UTC' +committers: + - <<: *opnfv_testresults_ptl + - name: 'Fatih Degirmenci' + company: 'Ericsson' + email: 'fatih.degirmenci@ericsson.com' + id: 'fdegir' + timezone: 'Europe/Stockholm' + - name: 'Morgan Richomme' + email: 'morgan.richomme@orange.com' + company: 'Orange' + id: 'mrichomme' + timezone: 'Europe/Paris' + - name: 'Jose Lausuch' + company: 'SUSE' + email: 'jalausuch@suse.com' + id: 'jose.lausuch' + timezone: 'Europe/Madrid' + - name: 'Jack Chan' + company: 'Huawei' + email: 'chenjiankun1@huawei.com' + id: 'chenjiankun' + timezone: 'China/Shanghai' diff --git a/reporting/html/colorado.html b/reporting/3rd_party/html/colorado.html index 7a7326e..7a7326e 100644 --- a/reporting/html/colorado.html +++ b/reporting/3rd_party/html/colorado.html diff --git a/reporting/html/danube.html b/reporting/3rd_party/html/danube.html index ae8a3ac..ae8a3ac 100644 --- a/reporting/html/danube.html +++ b/reporting/3rd_party/html/danube.html diff --git a/reporting/html/elements.html b/reporting/3rd_party/html/elements.html index 7b9bb4d..7b9bb4d 100644 --- a/reporting/html/elements.html +++ b/reporting/3rd_party/html/elements.html diff --git a/reporting/html/euphrates.html b/reporting/3rd_party/html/euphrates.html index e357edc..e357edc 100644 --- a/reporting/html/euphrates.html +++ b/reporting/3rd_party/html/euphrates.html diff --git a/reporting/html/fraser.html b/reporting/3rd_party/html/fraser.html index 65b996c..65b996c 100644 --- a/reporting/html/fraser.html +++ b/reporting/3rd_party/html/fraser.html diff --git a/reporting/html/functest.html b/reporting/3rd_party/html/functest.html index d5f78c5..d5f78c5 100644 --- a/reporting/html/functest.html +++ b/reporting/3rd_party/html/functest.html diff --git a/reporting/html/generic.html b/reporting/3rd_party/html/generic.html index 39273da..39273da 100644 --- a/reporting/html/generic.html +++ b/reporting/3rd_party/html/generic.html diff --git a/reporting/html/index.html b/reporting/3rd_party/html/index.html index 858ac47..858ac47 100644 --- a/reporting/html/index.html +++ b/reporting/3rd_party/html/index.html diff --git a/reporting/html/master.html b/reporting/3rd_party/html/master.html index 5d4f916..5d4f916 100644 --- a/reporting/html/master.html +++ b/reporting/3rd_party/html/master.html diff --git a/reporting/css/default.css b/reporting/css/default.css index e32fa5f..686e886 100644 --- a/reporting/css/default.css +++ b/reporting/css/default.css @@ -26,6 +26,7 @@ width: 100%; background-color: #0095a2 } + .panel-default > .panel-heading h4 { color: white; } @@ -55,7 +56,7 @@ td{ background-color: #0095a2; } -h1 { +h1 { display: block; font-size: 2em; margin-top: 0.67em; @@ -191,4 +192,3 @@ h2 { position:relative; top:1px; } - diff --git a/reporting/docker/reporting.sh b/reporting/docker/reporting.sh index ee9dccf..8008bf6 100755 --- a/reporting/docker/reporting.sh +++ b/reporting/docker/reporting.sh @@ -21,15 +21,10 @@ done # copy images, js, css, 3rd_party cp -Rf 3rd_party display cp -Rf css display -cp -Rf html/* display +cp -Rf 3rd_party/html/* display cp -Rf img display cp -Rf js display -for i in "${versions[@]}" -do - cp -Rf html/functest.html display/$i/functest -done - # if nothing is precised run all the reporting generation # projet | option # $1 | $2 diff --git a/reporting/js/gauge.js b/reporting/js/gauge.js index 4cad16c..a9842e5 100644 --- a/reporting/js/gauge.js +++ b/reporting/js/gauge.js @@ -28,7 +28,9 @@ var gauge = function(container) { labelFormat : d3.format(',g'), labelInset : 10, - arcColorFn : d3.interpolateHsl(d3.rgb('#ff0000'), d3.rgb('#00ff00')) + arcColorFn : d3.scale.quantile() + .domain([0, , 0.6, 0.8, 1]) + .range([d3.rgb('#ff0000'),d3.rgb('#ffcc00'),d3.rgb('#00ff00')]) }; diff --git a/reporting/reporting/bottlenecks/reporting-status.py b/reporting/reporting/bottlenecks/reporting-status.py index 225227a..8966d06 100644 --- a/reporting/reporting/bottlenecks/reporting-status.py +++ b/reporting/reporting/bottlenecks/reporting-status.py @@ -37,14 +37,10 @@ for version in VERSIONS: # For all the installers for installer in INSTALLERS: # get scenarios results data - if version != 'master': - new_version = "stable/{}".format(version) - else: - new_version = version scenario_results = rp_utils.getScenarios("bottlenecks", "posca_factor_ping", installer, - new_version) + version) LOGGER.info("scenario_results: %s", scenario_results) scenario_stats = rp_utils.getScenarioStats(scenario_results) diff --git a/reporting/reporting/functest/reporting-status.py b/reporting/reporting/functest/reporting-status.py index 592f929..e36aede 100755 --- a/reporting/reporting/functest/reporting-status.py +++ b/reporting/reporting/functest/reporting-status.py @@ -25,8 +25,6 @@ Functest reporting status LOGGER = rp_utils.getLogger("Functest-Status") # Initialization -testValid = [] -otherTestCases = [] reportingDate = datetime.datetime.now().strftime("%Y-%m-%d %H:%M") # init just connection_check to get the list of scenarios @@ -43,8 +41,7 @@ blacklist = rp_utils.get_config('functest.blacklist') log_level = rp_utils.get_config('general.log.log_level') exclude_noha = rp_utils.get_config('functest.exclude_noha') exclude_virtual = rp_utils.get_config('functest.exclude_virtual') - -functest_yaml_config = rp_utils.getFunctestConfig() +tiers_for_scoring = {'healthcheck', 'smoke', 'vnf', 'features'} LOGGER.info("*******************************************") LOGGER.info("* *") @@ -57,38 +54,36 @@ LOGGER.info("* NOHA scenarios excluded: %s *", exclude_noha) LOGGER.info("* *") LOGGER.info("*******************************************") -# Retrieve test cases of Tier 1 (smoke) -config_tiers = functest_yaml_config.get("tiers") +# For all the versions +for version in versions: + testValid = [] + # Retrieve test cases of Tier 1 (smoke) + version_config = "" + if (version != "master" and version != "latest"): + version_config = "?h=stable/" + version + functest_yaml_config = rp_utils.getFunctestConfig(version_config) + config_tiers = functest_yaml_config.get("tiers") + + # we consider Tier 0 (Healthcheck), Tier 1 (smoke),2 (features) + # to validate scenarios + # Tier > 2 are not used to validate scenarios but we display + # the results anyway + # tricky thing for the API as some tests are Functest tests + # other tests are declared directly in the feature projects + for tier in config_tiers: -# we consider Tier 0 (Healthcheck), Tier 1 (smoke),2 (features) -# to validate scenarios -# Tier > 2 are not used to validate scenarios but we display the results anyway -# tricky thing for the API as some tests are Functest tests -# other tests are declared directly in the feature projects -for tier in config_tiers: - if tier['order'] >= 0 and tier['order'] < 2: for case in tier['testcases']: + try: + dependencies = case['dependencies'] + except KeyError: + dependencies = "" if case['case_name'] not in blacklist: testValid.append(tc.TestCase(case['case_name'], "functest", - case['dependencies'])) - elif tier['order'] == 2: - for case in tier['testcases']: - if case['case_name'] not in blacklist: - otherTestCases.append(tc.TestCase(case['case_name'], - case['case_name'], - case['dependencies'])) - elif tier['order'] > 2: - for case in tier['testcases']: - if case['case_name'] not in blacklist: - otherTestCases.append(tc.TestCase(case['case_name'], - "functest", - case['dependencies'])) + dependencies, + tier=tier['name'])) + LOGGER.debug("Functest reporting start") -LOGGER.debug("Functest reporting start") - -# For all the versions -for version in versions: # For all the installers scenario_directory = "./display/" + version + "/functest/" scenario_file_name = scenario_directory + "scenario_history.txt" @@ -155,10 +150,8 @@ for version in versions: # Check if test case is runnable / installer, scenario # for the test case used for Scenario validation try: - # 1) Manage the test cases for the scenario validation - # concretely Tiers 0-3 for test_case in testValid: - test_case.checkRunnable(installer, s, + test_case.checkRunnable(installer, s, architecture, test_case.getConstraints()) LOGGER.debug("testcase %s (%s) is %s", test_case.getDisplayName(), @@ -169,7 +162,8 @@ for version in versions: name = test_case.getName() displayName = test_case.getDisplayName() project = test_case.getProject() - nb_test_runnable_for_this_scenario += 1 + if test_case.getTier() in tiers_for_scoring: + nb_test_runnable_for_this_scenario += 1 LOGGER.info(" Searching results for case %s ", displayName) if "fuel" in installer: @@ -185,53 +179,18 @@ for version in versions: LOGGER.info(" >>>> Test score = " + str(result)) test_case.setCriteria(result) test_case.setIsRunnable(True) - testCases2BeDisplayed.append(tc.TestCase(name, - project, - "", - result, - True, - 1)) - scenario_score = scenario_score + result - - # 2) Manage the test cases for the scenario qualification - # concretely Tiers > 3 - for test_case in otherTestCases: - test_case.checkRunnable(installer, s, - test_case.getConstraints()) - LOGGER.debug("testcase %s (%s) is %s", - test_case.getDisplayName(), - test_case.getName(), - test_case.isRunnable) - time.sleep(1) - if test_case.isRunnable: - name = test_case.getName() - displayName = test_case.getDisplayName() - project = test_case.getProject() - LOGGER.info(" Searching results for case %s ", - displayName) - if "fuel" in installer: - result = rp_utils.getCaseScoreFromBuildTag( - name, - s_result) - else: - result = rp_utils.getCaseScore(name, installer, - s, version) - # at least 1 result for the test - if result > -1: - test_case.setCriteria(result) - test_case.setIsRunnable(True) - testCases2BeDisplayed.append(tc.TestCase( - name, - project, - "", - result, - True, - 4)) - else: - LOGGER.debug("No results found") - - items[s] = testCases2BeDisplayed - except Exception: # pylint: disable=broad-except + testCases2BeDisplayed.append( + tc.TestCase(name, + project, + "", + result, + True, + tier=test_case.getTier())) + if test_case.getTier() in tiers_for_scoring: + scenario_score = scenario_score + result + + items[s] = testCases2BeDisplayed + except KeyError: # pylint: disable=broad-except LOGGER.error("Error installer %s, version %s, scenario %s", installer, version, s) LOGGER.error("No data available: %s", sys.exc_info()[0]) @@ -259,6 +218,12 @@ for version in versions: else: k_score = 2 + # TODO for the scoring we should consider 3 tiers + # - Healthcheck + # - Smoke + # - Vnf + # components + scenario_criteria = nb_test_runnable_for_this_scenario*k_score # score for reporting diff --git a/reporting/reporting/functest/template/index-status-tmpl.html b/reporting/reporting/functest/template/index-status-tmpl.html index 50fc648..48b5a2d 100644 --- a/reporting/reporting/functest/template/index-status-tmpl.html +++ b/reporting/reporting/functest/template/index-status-tmpl.html @@ -144,33 +144,32 @@ $(document).ready(function (){ <span class="panel-header-item"> </span> </div> + {% for tier in ['healthcheck', 'smoke', 'vnf', 'features'] -%} <table class="table"> <tr> + <h2>{{tier}}</h2> {% for test in items[scenario] -%} - <th> - {% if test.getCriteria() > -1 -%} - {{test.getDisplayName() }} + {% if test.getCriteria() > -1 and test.getTier() == tier -%} + <th>{{test.getDisplayName() }}</th> {%- endif %} - {% if test.getTier() > 3 -%} - * - {%- endif %} - </th> - {%- endfor %} + {%- endfor %} </tr> <tr class="tr-weather-weather"> - {% for test in items[scenario] -%} - {% if test.getCriteria() > 2 -%} + {% for test in items[scenario] -%} + {% if test.getCriteria() > 2 and test.getTier() == tier -%} <td><img src="../../img/weather-clear.png"></td> - {%- elif test.getCriteria() > 1 -%} + {%- elif test.getCriteria() > 1 and test.getTier() == tier -%} <td><img src="../../img/weather-few-clouds.png"></td> - {%- elif test.getCriteria() > 0 -%} + {%- elif test.getCriteria() > 0 and test.getTier() == tier -%} <td><img src="../../img/weather-overcast.png"></td> - {%- elif test.getCriteria() > -1 -%} + {%- elif test.getCriteria() > -1 and test.getTier() == tier -%} <td><img src="../../img/weather-storm.png"></td> {%- endif %} {%- endfor %} </tr> </table> + <br><hr> + {%- endfor %} </div> </div> {%- endfor %} diff --git a/reporting/reporting/functest/testCase.py b/reporting/reporting/functest/testCase.py index a182dd4..fba3216 100644 --- a/reporting/reporting/functest/testCase.py +++ b/reporting/reporting/functest/testCase.py @@ -26,7 +26,9 @@ class TestCase(object): 'onos': 'ONOS', 'ocl': 'OCL', 'tempest_smoke_serial': 'Tempest (smoke)', + 'tempest_smoke': 'Tempest (smoke)', 'tempest_full_parallel': 'Tempest (full)', + 'tempest_full': 'Tempest (full)', 'tempest_defcore': 'Tempest (Defcore)', 'refstack_defcore': 'Refstack', 'rally_sanity': 'Rally (smoke)', @@ -43,20 +45,45 @@ class TestCase(object): 'functest-odl-sfc': 'SFC', 'onos_sfc': 'SFC', 'parser-basics': 'Parser', - 'connection_check': 'Health (connection)', - 'api_check': 'Health (api)', + 'connection_check': 'connectivity', + 'api_check': 'api', 'snaps_smoke': 'SNAPS', - 'snaps_health_check': 'Health (dhcp)', + 'snaps_health_check': 'dhcp', 'gluon_vping': 'Netready', 'fds': 'FDS', 'cloudify_ims': 'vIMS (Cloudify)', + 'cloudify': 'Cloudify', 'orchestra_openims': 'OpenIMS (OpenBaton)', 'orchestra_clearwaterims': 'vIMS (OpenBaton)', 'opera_ims': 'vIMS (Open-O)', 'vyos_vrouter': 'vyos (Cloudify)', 'barometercollectd': 'Barometer', 'odl_netvirt': 'Netvirt', - 'security_scan': 'Security'} + 'security_scan': 'Security', + 'patrole': 'Patrole', + 'tenantnetwork1': 'tenant network 1', + 'tenantnetwork2': 'tenant network 2', + 'vmready1': 'vm ready 1', + 'vmready2': 'vm ready 2', + 'singlevm1': 'single vm 1', + 'singlevm2': 'single vm 2', + 'cinder_test': 'cinder tests', + 'barbican': 'barbican', + 'vmtp': 'vmtp', + 'juju_epc': 'vEPC (Juju)', + 'shaker': 'shaker', + 'neutron_trunk': 'Neutron trunk', + 'tempest_scenario': 'tempest_scenario', + 'networking-bgpvpn': 'networking-bgpvpn', + 'networking-sfc': 'networking-sfc', + 'tempest_full': 'Tempest (full)', + 'cloudify': 'cloudify', + 'heat_ims': 'vIMS (Heat)', + 'vmtp': 'vmtp', + 'tempest_smoke': 'Tempest (smoke)', + 'neutron-tempest-plugin-api': 'Neutron API', + 'vgpu': 'vgpu', + 'stor4nfv_os': 'stor4nfv_os'} try: self.displayName = display_name_matrix[self.name] except: @@ -68,22 +95,22 @@ class TestCase(object): def getProject(self): return self.project - def getConstraints(self): - return self.constraints - def getCriteria(self): return self.criteria def getTier(self): return self.tier + def getConstraints(self): + return self.constraints + def setCriteria(self, criteria): self.criteria = criteria def setIsRunnable(self, isRunnable): self.isRunnable = isRunnable - def checkRunnable(self, installer, scenario, config): + def checkRunnable(self, installer, scenario, arch, config): # Re-use Functest declaration # Retrieve Functest configuration file functest_config.yaml is_runnable = True @@ -98,27 +125,36 @@ class TestCase(object): # Retrieve test constraints # Retrieve test execution param - test_execution_context = {"installer": installer, - "scenario": scenario} + test_execution_context = {"INSTALLER_TYPE": installer, + "DEPLOY_SCENARIO": scenario, + "POD_ARCH": arch} + + # 3 types of constraints + # INSTALLER_TYPE + # DEPLOY_SCENARIO + # POD_ARCH # By default we assume that all the tests are always runnable... # if test_env not empty => dependencies to be checked - if config_test is not None and len(config_test) > 0: - # possible criteria = ["installer", "scenario"] - # consider test criteria from config file - # compare towards CI env through CI en variable - for criteria in config_test: - if re.search(config_test[criteria], - test_execution_context[criteria]) is None: - # print "Test "+ test + " cannot be run on the environment" - is_runnable = False + try: + if config_test is not None and len(config_test) > 0: + # possible criteria = ["installer", "scenario"] + # consider test criteria from config file + # compare towards CI env through CI en variable + for criterias in config_test: + for criteria_key, criteria_value in criterias.iteritems(): + if re.search( + criteria_value, + test_execution_context[criteria_key]) is None: + is_runnable = False + except AttributeError: + is_runnable = False # print is_runnable self.isRunnable = is_runnable def toString(self): testcase = ("Name=" + self.name + ";Criteria=" + str(self.criteria) + ";Project=" + self.project + - ";Constraints=" + str(self.constraints) + ";IsRunnable" + str(self.isRunnable)) return testcase diff --git a/reporting/reporting/reporting.yaml b/reporting/reporting/reporting.yaml index b2f7d07..ce27b90 100644 --- a/reporting/reporting/reporting.yaml +++ b/reporting/reporting/reporting.yaml @@ -36,9 +36,11 @@ testapi: functest: blacklist: - odl_netvirt - - juju_epc - tempest_full_parallel + - tempest_full - rally_full + - heat_ims + - tempest_scenario max_scenario_criteria: 50 test_conf: https://git.opnfv.org/cgit/functest/plain/functest/ci/testcases.yaml log_level: ERROR diff --git a/reporting/reporting/vsperf/reporting-status.py b/reporting/reporting/vsperf/reporting-status.py index f1a437f..b45595d 100644 --- a/reporting/reporting/vsperf/reporting-status.py +++ b/reporting/reporting/vsperf/reporting-status.py @@ -127,7 +127,7 @@ def main(): period=50) version_data = _get_version_data(data['vsperf']) - for version in {'master', 'danube', 'euphrates', 'fraser'}: + for version in {'master', 'euphrates', 'fraser'}: _generate_reporting(version, version_data.get(version, [])) LOG.info("End") diff --git a/testapi/3rd_party/static/testapi-ui/assets/css/style.css b/testapi/3rd_party/static/testapi-ui/assets/css/style.css index fb21399..2b20d6b 100644 --- a/testapi/3rd_party/static/testapi-ui/assets/css/style.css +++ b/testapi/3rd_party/static/testapi-ui/assets/css/style.css @@ -292,4 +292,53 @@ json-tree .key { json-tree .leaf-value{ word-break: normal!important; +} + +#toast { + visibility: hidden; + min-width: 250px; + margin-left: -125px; + color: #fff; + text-align: center; + border-radius: 10px; + padding: 16px; + position: fixed; + z-index: 9999; + left: 50%; + bottom: 30px; +} + +#toast.error{ + background-color: #B03838; +} + +#toast.success{ + background-color: #1A911E; +} + +#toast.show { + visibility: visible; + + -webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s; + animation: fadein 0.5s, fadeout 0.5s 2.5s; +} + +@-webkit-keyframes fadein { + from {bottom: 0; opacity: 0;} + to {bottom: 30px; opacity: 1;} +} + +@keyframes fadein { + from {bottom: 0; opacity: 0;} + to {bottom: 30px; opacity: 1;} +} + +@-webkit-keyframes fadeout { + from {bottom: 30px; opacity: 1;} + to {bottom: 0; opacity: 0;} +} + +@keyframes fadeout { + from {bottom: 30px; opacity: 1;} + to {bottom: 0; opacity: 0;} }
\ No newline at end of file diff --git a/testapi/docker/Dockerfile b/testapi/docker/Dockerfile index bbf12fc..dccc162 100644 --- a/testapi/docker/Dockerfile +++ b/testapi/docker/Dockerfile @@ -40,7 +40,7 @@ python-pip \ crudini \ --no-install-recommends -RUN pip install --upgrade pip requests +RUN pip install --upgrade requests RUN git config --global http.sslVerify false RUN git clone https://gerrit.opnfv.org/gerrit/releng-testresults /home/releng-testresults @@ -48,5 +48,10 @@ RUN git clone https://gerrit.opnfv.org/gerrit/releng-testresults /home/releng-te WORKDIR /home/releng-testresults/testapi RUN pip install -r requirements.txt +# bugfix +# SSLError: hostname 'identity.linuxfoundation.org' doesn't match 'c.sni.fastly.net' +# hope it is a temprary, try to fix it in upstream python-cas lib +RUN sed -i '152,152s/)/,\ verify=False)/g' /usr/local/lib/python2.7/dist-packages/cas.py + RUN python setup.py install CMD ["bash", "docker/start-server.sh"] diff --git a/testapi/docs/developer/devguide/images/CAS-sequence.jpg b/testapi/docs/developer/devguide/images/CAS-sequence.jpg Binary files differnew file mode 100644 index 0000000..a624871 --- /dev/null +++ b/testapi/docs/developer/devguide/images/CAS-sequence.jpg diff --git a/testapi/docs/developer/devguide/testapi-client-import.rst b/testapi/docs/developer/devguide/testapi-client-import.rst new file mode 100644 index 0000000..c6d7311 --- /dev/null +++ b/testapi/docs/developer/devguide/testapi-client-import.rst @@ -0,0 +1,974 @@ +.. This work is licensed under a Creative Commons Attribution 4.0 International License. +.. http://creativecommons.org/licenses/by/4.0 +.. (c) 2017 ZTE Corp. + +===================== +TestAPI client import +===================== + +**Python module to communicate with the TestAPI Server** + +This project aims to provide a python module which can +communicate with the TestAPI Server. The user can use this client +to fetch/post/modify the resources on the TestAPI Server. + +Usage +----- + +Pod +^^^ + +GET +""" + +Get a list of all the declared pods from the TestAPI server. + +.. code-block:: shell + + from testapiclient.client import pods + + pod_client = pods.PodsClient() + pod_client.get() + +The user can filter the results by the name attribute. Backend will +use a regular expression to find the list of pods which are +related to given name. + +.. code-block:: shell + + from testapiclient.client import pods + + pod_client = pods.PodsClient() + pod_client.get(name='pod1') + +.. NOTE:: + Response format: [{"_id": "", "creator": "", "role": "", "name": "", + "details": "", "mode": "", "creation_date": ""}] + + +GET ONE +""""""" + +Get a specific pod by its name. + +.. code-block:: shell + + from testapiclient.client import pods + + pod_client = pods.PodsClient() + pod_client.get_one('name') + +.. NOTE:: + Response format: {"_id": "", "creator": "", "role": "", "name": "", + "details": "", "mode": "", "creation_date": ""} + +CREATE +"""""" +This method used to create a project on the server. +The user should provide the user parameter and the password +parameter while initiating the PodsClient. + +Input for the function : + + * pod-json : Json object of the project + +.. NOTE:: + pod-json-schema - '{"role": "", "name": "", "details": "", "mode": ""}' + + * role should be either "community-ci" or "production-ci" + * mode should be either "metal" or "virtual" + +.. code-block:: shell + + from testapiclient.client import pods + + pod_client = pods.PodsClient(user='test', password='pass') + pod_client.create({'name': 'test-api', 'mode':'metal', + 'role':'community_ci', 'details':''}) + + +Project +^^^^^^^ + +GET +""" + +Get a list of all the declared projects from the TestAPI server. + +.. code-block:: shell + + from testapiclient.client import projects + + project_client = projects.ProjectsClient() + project_client.get() + +User can filter the results by the name attribute. Backend will +use a regular expression to find the list of projects which are +related to given name. + +.. code-block:: shell + + from testapiclient.client import projects + + project_client = projects.ProjectsClient() + project_client.get(name='project1') + +.. NOTE:: + Response format: [{"_id": "", "creator": "", "description": "", + "name": "", "creation_date": ""}] + +GET ONE +""""""" + +Get a specific project by its name. + +.. code-block:: shell + + from testapiclient.client import projects + + project_client = projects.ProjectsClient() + project_client.get_one('name') + +.. NOTE:: + Response format: {"_id": "", "creator": "", "description": "", + "name": "", "creation_date": ""} + +CREATE +"""""" + +This method used to create a project on the server. +The user should provide the user parameter and the password +parameter while initiating the ProjectsClient. + +Input for the function : + + * project-json : Json object of the project + +.. NOTE:: + project-json schema - '{"description": "", "name": ""}' + +.. code-block:: shell + + from testapiclient.client import projects + + project_client = projects.ProjectsClient(user='test', password='pass') + project_client.create({'name': 'functest', 'description':'sample text'} + +UPDATE +"""""" + +This method used to update an existing project on the server. +The user should provide the user parameter and the password +parameter while initiating the ProjectsClient. + +Input for the function : + + * project-name: name of the project which user want to update. + * project-json: Json object of the project + +.. NOTE:: + project-json schema - '{"description": "", "name": ""}' + +.. code-block:: shell + + from testapiclient.client import projects + + project_client = projects.ProjectsClient(user='test', password='pass') + project_client.update('functest', {'name': 'functest', + 'description':'updated text'}) + +DELETE +"""""" + +This method used to delete an existing project on the server. +The user should provide the user parameter and the password +parameter while initiating the ProjectsClient. + +Input for the function : + + * project-name: name of the project which user want to delete. + +.. code-block:: shell + + from testapiclient.client import projects + + project_client = projects.ProjectsClient(user='test', password='pass') + project_client.delete('functest') + + +Testcase +^^^^^^^^ + +GET +""" + +Get a list of all the declared testcases under a project +from the TestAPI server. + +Input for the function : + + * project_name : Name of the project + +.. code-block:: shell + + from testapiclient.client import testcases + + testcase_client = testcases.TestcasesClient() + testcase_client.get(project_name='functest') + + +.. NOTE:: + Response format: [{ "project_name": "functest", "run": "", + "description": "", "tags": "", "creation_date": "", + "dependencies": "", "tier": "", "trust": "", "blocking": "", + "name": "", "ci_loop": "", "url": "", "version": "", + "criteria": "", "domains": "", "_id": "", "catalog_description": ""}] + +GET ONE +""""""" + +Get a specific testcase by its name and project name. + +.. code-block:: shell + + from testapiclient.client import testcases + + testcase_client = testcases.TestcasesClient() + testcase_client.get_one(project_name='functest', case_name='name') + +.. NOTE:: + Response format: { "project_name": "functest", "run": "", + "description": "", "tags": "", "creation_date": "", + "dependencies": "", "tier": "", "trust": "", "blocking": "", + "name": "", "ci_loop": "", "url": "", "version": "", + "criteria": "", "domains": "", "_id": "", "catalog_description": ""} + +CREATE +"""""" + +This method used to create a testcase on the server. +The user should provide the user parameter and the password +parameter while initiating the TestcasesClient. + +Input for the function : + * project_name : Project name + * testcase_json : Json object of the testcase + +.. NOTE:: + testcase_json schema - '{ "run": "", "description": "", "tags": "", + "dependencies": "", "tier": "", "trust": "", "blocking": "", + "name": "", "ci_loop": "", "url": "", "version": "", + "criteria": "", "domains": "", "catalog_description": ""}' + +.. code-block:: shell + + from testapiclient.client import testcases + + testcase_client = testcases.TestcasesClient(user='test', password='pass') + testcase_client.create(project_name, testcase_json) + +UPDATE +"""""" + +This method used to update an existing testcase on the server. +The user should provide the user parameter and the password +parameter while initiating the TestcasesClient. + +Input for the function : + * project_name : Project name + * testcase_name: name of the testcase which user want to update. + * testcase_json: Json object of the testcase + +.. NOTE:: + testcase-json schema - '{ "run": "", "description": "", "tags": "", + "dependencies": "", "tier": "", "trust": "", "blocking": "", + "name": "", "ci_loop": "", "url": "", "version": "", + "criteria": "", "domains": "", "catalog_description": ""}' + +.. code-block:: shell + + from testapiclient.client import testcases + + testcase_client = testcases.TestcasesClient(user='test', password='pass') + testcase_client.update(project_name, testcase_name, testcase_json) + +DELETE +"""""" + +This method used to delete an existing testcase on the server. +The user should provide the user parameter and the password +parameter while initiating the TestcasesClient. + +Input for the function : + + * project_name: name of the project + * testcase_name: name of the testcase which user want to delete. + +.. code-block:: shell + + from testapiclient.client import testcases + + testcase_client = testcases.TestcasesClient(user='test', password='pass') + testcase_client.delete(project_name, testcase_name) + + +Result +^^^^^^^ + +GET +""" + +Get a list of all the declared results from the TestAPI server. + +.. code-block:: shell + + from testapiclient.client import results + + result_client = results.ResultsClient() + result_client.get() + +User can filter the results by using some attributes. + +.. NOTE:: + List of search attributes. + + * case : Search results using tesetcase + * build-tag : Search results using build tag + * from : Search results using from date + * last : Search results using last date + * scenario : Search results using scenario + * period : Search results using period + * project : Search results using project + * to : Search results using to + * version : Search results using version + * criteria : Search results using criteria + * installer : Search results using installer + * pod : Search results using pod + * page : Search results using page + +.. code-block:: shell + + from testapiclient.client import results + + result_client = results.ResultsClient() + result_client.get(pod='pod1', project='project1') + + +.. NOTE:: + Response format: [{ "project_name": "", "scenario": "", + "stop_date": "", "case_name": "", "build_tag": "", + "version": "", "pod_name": "", "criteria": "", + "installer": "", "start_date": "", "details": ""}] + +GET ONE +""""""" + +Get a specific result by its id. + +.. code-block:: shell + + from testapiclient.client import results + + result_client = results.ResultsClient() + result_client.get_one(result_id) + +.. NOTE:: + Response format: { "project_name": "", "scenario": "", + "stop_date": "", "case_name": "", "build_tag": "", + "version": "", "pod_name": "", "criteria": "", + "installer": "", "start_date": "", "details": ""} + +CREATE +"""""" + +This method used to create a result on the server. +The user should provide a valid token to run this method. +Read testapi-client.rst to more details. + +Input for the function : + * result_json : Json object of the result + +.. NOTE:: + result_json schema - '{ "project_name": "", "scenario": "", + "stop_date": "", "case_name": "", "build_tag": "", + "version": "", "pod_name": "", "criteria": "", + "installer": "", "start_date": "", "details": ""}' + +.. code-block:: shell + + from testapiclient.client import results + + result_client = results.ResultsClient() + result_client.create(result_json) + +DeployResult +^^^^^^^^^^^^ + +GET +""" + +Get a list of all the declared deploy results from the TestAPI server. + +.. code-block:: shell + + from testapiclient.client import deploy_results + + deploy_result_client = deploy_results.DeployResultsClient() + deploy_result_client.get() + +User can filter the deploy results by using some attributes. + +.. NOTE:: + List of search attributes. + + * job-name : Search results using job + * build_id : Search results using build id + * from : Search results using from date + * last : Search results using last date + * scenario : Search results using scenario + * period : Search results using period + * to : Search results using to + * version : Search results using version + * criteria : Search results using criteria + * installer : Search results using installer + * pod_name : Search results using pod + * page : Search results using page + +.. code-block:: shell + + from testapiclient.client import deploy_results + + deploy_result_client = deploy_results.DeployResultsClient() + deploy_result_client.get(scenario='scenario1', installer='installer1') + + +.. NOTE:: + Response format: [{"build_id": "", "upstream_build_id": "", + "scenario": "", "stop_date": "", "start_date": "", + "upstream_job_name": "", "version": "", "pod_name": "", + "criteria": "", "installer": "", "_id": "", "job_name": "", + "details": ""}] + +GET ONE +""""""" + +Get a specific deploy result by its id. + +.. code-block:: shell + + from testapiclient.client import deploy_results + + deploy_result_client = deploy_results.DeployResultsClient() + deploy_result_client.get_one(deploy_result_id) + +.. NOTE:: + Response format: {"build_id": "", "upstream_build_id": "", + "scenario": "", "stop_date": "", "start_date": "", + "upstream_job_name": "", "version": "", "pod_name": "", + "criteria": "", "installer": "", "_id": "", "job_name": "", + "details": ""} + +CREATE +"""""" + +This method used to create a deploy_result on the server. +The user should provide a valid token to run this method. +Read testapi-client.rst to more details. + +Input for the function : + * deploy_result_json : Json object of the deploy_result + +.. NOTE:: + deploy_result_json schema - '{"build_id": "", "upstream_build_id": "", + "scenario": "", "stop_date": "", "start_date": "", + "upstream_job_name": "", "version": "", "pod_name": "", + "criteria": "", "installer": "", "job_name": "", + "details": ""}' + +.. code-block:: shell + + from testapiclient.client import deploy_results + + deploy_result_client = deploy_results.DeployResultsClient() + deploy_result_client.create(deploy_result_json) + +Scenario +^^^^^^^^ + +GET +""" + +Get a list of all the declared scenarios from the TestAPI server. + +.. code-block:: shell + + from testapiclient.client import scenarios + + scenario_client = scenarios.ScenariosClient() + scenario_client.get() + +User can filter the scenarios by using some attributes. + +.. NOTE:: + List of search attributes. + + * project : Search scenarios using project + * installer : Search scenarios using project + * version : Search scenarios using project + * name: Search scenarios using project + +.. code-block:: shell + + from testapiclient.client import scenarios + + scenario_client = scenarios.ScenariosClient() + scenario_client.get(name='scenario1') + +.. NOTE:: + Response format: [{ "installers": [], "_id": "", "creation_date": "", + "name": "", "creator": ""}] + +GET ONE +""""""" + +Get a specific scenario by its name. + +.. code-block:: shell + + from testapiclient.client import scenarios + + scenario_client = scenarios.ScenariosClient() + scenario_client.get_one('name') + +.. NOTE:: + Response format: { "installers": [], "_id": "", "creation_date": "", + "name": "", "creator": ""} + +CREATE +"""""" + +This method used to create a scenario on the server. +The user should provide the user parameter and the password +parameter while initiating the ScenariosClient. + +Input for the function : + + * scenario-json : Json object of the scenario + +.. NOTE:: + scenario_json schema - '{ "installers": [], + "name": ""}' + + See Installer for installer_schema + +.. code-block:: shell + + from testapiclient.client import scenarios + + scenario_client = scenarios.ScenariosClient(user='test', password='pass') + scenario_client.create(scenario_json) + +UPDATE +"""""" + +This method used to update the name of an existing scenario on the server. +The user should provide the user parameter and the password +parameter while initiating the ScenariosClient. + +Input for the function : + + * scenario-name: name of the scenario which user want to update. + * scenario-json: Json object of the scenario + +.. NOTE:: + * scenario_name + * scenario_update_json schema - '{"name": ""}' + +.. code-block:: shell + + from testapiclient.client import scenarios + + scenario_client = scenarios.ScenariosClient(user='test', password='pass') + scenario_client.update(scenario_name, scenario_update_json) + +DELETE +"""""" + +This method used to delete an existing scenario on the server. +The user should provide the user parameter and the password +parameter while initiating the ScenariosClient. + +Input for the function : + + * scenario_name: name of the scenario which user want to delete. + +.. code-block:: shell + + from testapiclient.client import scenarios + + scenario_client = scenarios.ScenariosClient(user='test', password='pass') + scenario_client.delete('scenario_name') + +Scenario Installer +^^^^^^^^^^^^^^^^^^ + +CREATE +"""""" + +This method used to create an installer under a scenario +on the server. The user should provide the user parameter +and the password parameter while initiating the InstallersClient. + +Input for the function : + * scenario_name + * installer-json : Json object of the installer + +.. NOTE:: + installer_json schema - '{ "versions": [], + "installer": ""}' + + See version for version_schema + +.. code-block:: shell + + from testapiclient.client import installers + + installer_client = installers.InstallersClient(user='test', password='pass') + installer_client.create(scenario_name, installer_json) + +UPDATE +"""""" + +This method used to update the all existing installers of a scenario +The user should provide the user parameter and the password +parameter while initiating the InstallersClient. + +Input for the function : + + * scenario_name + * installer-json: Json object of the installer + +.. NOTE:: + * scenario_name + * installer_json schema - [{ "versions": [], "installer": ""}] + +.. code-block:: shell + + from testapiclient.client import installers + + installer_client = installers.InstallersClient(user='test', password='pass') + installer_client.update(scenario_name, installer_update_json) + +DELETE +"""""" + +This method used to delete existing installers from a scenario. +on the server. +The user should provide the user parameter and the password +parameter while initiating the InstallersClient. + +Input for the function : + * scenario_name + * installer_names: names of the installer which user want to delete. + +.. code-block:: shell + + from testapiclient.client import installers + + installer_client = installers.InstallersClient(user='test', password='pass') + installer_client.delete(scenario_name, installer_names) + +Scenario Version +^^^^^^^^^^^^^^^^ + +CREATE +"""""" + +This method used to create a version under a scenario +on the server. The user should provide the user parameter +and the password parameter while initiating the VersionsClient. + +Input for the function : + + * scenario_name + * installer_name + * version-json : Json object of the version + +.. NOTE:: + version_json schema - '{ "projects": [], "owner": "", + "version": ""}' + + See version for version_schema + +.. code-block:: shell + + from testapiclient.client import versions + + version_client = versions.VersionsClient(user='test', password='pass') + version_client.create(scenario_name, installer_name, version_json) + +UPDATE +"""""" + +This method used to update the all existing versions of a scenario +The user should provide the user parameter and the password +parameter while initiating the VersionsClient. + +Input for the function : + + * scenario_name + * installer_name + * version-json: Json object of the version + +.. NOTE:: + * scenario_name + * version_json schema - [{ "projects": [], "owner": "", "version": ""}] + +.. code-block:: shell + + from testapiclient.client import versions + + version_client = versions.VersionsClient(user='test', password='pass') + version_client.update(scenario_name, installer_name, version_update_json) + +DELETE +"""""" + +This method used to delete existing versions from a scenario. +on the server. +The user should provide the user parameter and the password +parameter while initiating the VersionsClient. + +Input for the function : + * scenario_name + * installer_name + * version_names: names of the version which user want to delete. + +.. code-block:: shell + + from testapiclient.client import versions + + version_client = versions.VersionsClient(user='test', password='pass') + version_client.delete(scenario_name, installer_name, version_names) + +Scenario Project +^^^^^^^^^^^^^^^^ + +CREATE +"""""" + +This method used to create a project under a scenario +on the server. The user should provide the user parameter +and the password parameter while initiating the ProjectsClient. + +Input for the function : + + * scenario_name + * installer_name + * version_name + * project-json : Json object of the project + +.. NOTE:: + project_json schema - '{ "scores": [], "trust_indcators": [], + "customs": [], "project": ""}' + + See project for project_schema + +.. code-block:: shell + + from testapiclient.client import projects + + project_client = projects.ProjectsClient(user='test', password='pass') + project_client.create(scenario_name, installer_name, version_name, project_json) + +UPDATE +"""""" + +This method used to update the all existing projects of a scenario +The user should provide the user parameter and the password +parameter while initiating the ProjectsClient. + +Input for the function : + + * scenario_name + * installer_name + * version_name + * project-json: Json object of the project + +.. NOTE:: + * scenario_name + * project_json schema - [{"scores": [], "trust_indcators": [], "customs": [], "project": ""}] + +.. code-block:: shell + + from testapiclient.client import projects + + project_client = projects.ProjectsClient(user='test', password='pass') + project_client.update(scenario_name, installer_name, version_name, project_update_json) + +DELETE +"""""" + +This method used to delete existing projects from a scenario. +on the server. +The user should provide the user parameter and the password +parameter while initiating the ProjectsClient. + +Input for the function : + * scenario_name + * installer_name + * version_name + * project_names: names of the project which user want to delete. + +.. code-block:: shell + + from testapiclient.client import projects + + project_client = projects.ProjectsClient(user='test', password='pass') + project_client.delete(scenario_name, installer_name, version_name, project_names) + +Scenario Custom +^^^^^^^^^^^^^^^ + +CREATE +"""""" + +This method used to create a custom under a scenario +on the server. The user should provide the user parameter +and the password parameter while initiating the CustomsClient. + +Input for the function : + + * scenario_name + * installer_name + * version_name + * project_name + * custom : List of Customs + +.. NOTE:: + * scenario_name + * custom schema - ["List of Strings"] + + See custom for custom_schema + +.. code-block:: shell + + from testapiclient.client import customs + + custom_client = customs.CustomsClient(user='test', password='pass') + custom_client.create(scenario_name, installer_name, version_name, + project_name, custom_json) + +UPDATE +"""""" + +This method used to update the all existing customs of a scenario +The user should provide the user parameter and the password +parameter while initiating the CustomsClient. + +Input for the function : + + * scenario_name + * installer_name + * version_name + * project_name + * custom : List of Customs + +.. NOTE:: + * scenario_name + * custom schema - ["List of Strings"] + +.. code-block:: shell + + from testapiclient.client import customs + + custom_client = customs.CustomsClient(user='test', password='pass') + custom_client.update(scenario_name, installer_name, version_name, + project_name custom) + +DELETE +"""""" + +This method used to delete existing customs from a scenario. +on the server. +The user should provide the user parameter and the password +parameter while initiating the CustomsClient. + +Input for the function : + * scenario_name + * installer_name + * version_name + * project_name + * custom: custom which user want to delete. + +.. code-block:: shell + + from testapiclient.client import customs + + custom_client = customs.CustomsClient(user='test', password='pass') + custom_client.delete(scenario_name, installer_name, version_name, + project_name, customs) + +Scenario Scores +^^^^^^^^^^^^^^^ + +CREATE +"""""" + +This method used to create a score under a scenario +on the server. The user should provide the user parameter +and the password parameter while initiating the ScoresClient. + +Input for the function : + + * scenario_name + * installer_name + * version_name + * project_name + * score_json : Schema for the score + +.. NOTE:: + * scenario_name + * score_json schema - '{ "date": "", "score": ""}' + + See score for score_schema + +.. code-block:: shell + + from testapiclient.client import scores + + score_client = scores.ScoresClient(user='test', password='pass') + score_client.create(scenario_name, installer_name, version_name, + project_name, score_json) + +Scenario TrustIndicator +^^^^^^^^^^^^^^^^^^^^^^^ + +CREATE +"""""" + +This method used to create a trust indicator under a scenario +on the server. The user should provide the user parameter +and the password parameter while initiating the TrustIndicatorsClient. + +Input for the function : + + * scenario_name + * installer_name + * version_name + * project_name + * trust_indicator_json : Schema for the trust_indicator + +.. NOTE:: + * scenario_name + * trust_indicator_json schema - '{ "date": "", "status": ""}' + + See trust_indicator for trust_indicator_schema + +.. code-block:: shell + + from testapiclient.client import trust_indicators + + trust_indicator_client = trust_indicators.TrustIndicatorsClient(user='test', password='pass') + trust_indicator_client.create(scenario_name, installer_name, version_name, + project_name, trust_indicator_json)
\ No newline at end of file diff --git a/testapi/docs/developer/devguide/testapi-client.rst b/testapi/docs/developer/devguide/testapi-client.rst index ab4c8e8..5ba5df3 100644 --- a/testapi/docs/developer/devguide/testapi-client.rst +++ b/testapi/docs/developer/devguide/testapi-client.rst @@ -6,5 +6,859 @@ TestAPI client ============== -.. toctree:: - :maxdepth: 2 +TestAPIClient is a command-line client for TestAPI that +brings the command set for pod, project, testcase, results, +deploy result and scenario together in a single shell with a uniform command +structure. + + +Installation +------------ + +User can install this client from the source. + +.. code-block:: shell + + python install testapi/testapi-client/setup.py install + +After the installation, user has to set the environment variables + +.. code-block:: shell + + source testapi/testapi-client/etc/client.creds + + +Authentication Process +---------------------- + +User needs to provide the username and the password with the testapi +command. + +.. code-block:: shell + + $ testapi -u [username] -p [password] + (testapi) pod create + + +or + +.. code-block:: shell + + testapi pode create -u [username] -p [password] [pod-schema] + +First one, user can continue the progress after the authentication. +cli will create a new session to handle the request. + +In second one, cli won't create a session. one time command. + +Token is also used for the authorization purpose. User has to obtain the +valid token from the TestAPI comminity and set it in the following file +: **testapi/testapi-client/etc/client.creds** + +.. code-block:: shell + + source testapi/testapi-client/etc/client.creds + + +Command Structure +----------------- + +TestAPIClient follows a common command Structure. + +.. code-block:: shell + + testapi [resource-name] [function] [-u] [username] [-p] [password] + [command-arguments] + +.. NOTE:: + resource-name : include first order parent name and resource name. + + example: + scenario installer, scenario version, scenario project, scenario custom, + scenario trustindicator, scenario score, pod , project, testcase, result, + deployresult and scenario. + +.. NOTE:: + -u and -p are optional commands. The user can decide on them. + +There are many arguments for each commands. User can get them using +help command in the cli. + +.. code-block:: shell + + pod create --help/-h + +Pod +^^^ + +Create +"""""" + +Authentication required + +.. code-block:: shell + + testapi pod create [-u] [username] [-p] [password] [pod-schema] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) pod create [pod-schema] + +.. NOTE:: + pod-schema - '{"role": "", "name": "", "details": "", "mode": ""}' + +Get +""" + +Authentication is not required + +.. code-block:: shell + + testapi pod get [-name] [key-word] + +.. NOTE:: + -name is not mandatory. The user can use the -name option to reduce the + search result otherwise they will get the details about all pods. + +Get one +""""""" + +Authentication is not required + +.. code-block:: shell + + testapi pod getone [name-keyword] + +.. NOTE:: + name-keyword is mandatory. + + +Delete +"""""" + +Authentication is required + +.. code-block:: shell + + testapi pod delete [-u] [username] [-p] [password] [pod-name] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) pod delete [pod-name] + +.. NOTE:: + pod-name is mandatory. + + +Project +^^^^^^^ + +Create +"""""" + +Authentication required + +.. code-block:: shell + + testapi project create [-u] [username] [-p] [password] [project-schema] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) project create [project-schema] + +.. NOTE:: + project-schema - '{"description": "", "name": ""}' + + +Get +""" + +Authentication is not required + +.. code-block:: shell + + testapi project get [-name] [key-word] + +.. NOTE:: + -name is not mandatory. The user can use the -name option to reduce the + search result otherwise they will get the details about all projects. + +Get one +""""""" + +Authentication is not required + +.. code-block:: shell + + testapi project getone [name-keyword] + +.. NOTE:: + name-keyword is mandatory. + +Update +"""""" + +Authentication required + +.. code-block:: shell + + testapi project put [-u] [username] [-p] [password] [project-name] + [project-schema] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) project put [project-name] [project-schema] + +.. NOTE:: + project-schema - '{"name": "", "description": ""}' + +Delete +"""""" + +Authentication is required + +.. code-block:: shell + + testapi project delete [-u] [username] [-p] [password] [project-name] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) project delete [project-name] + +.. NOTE:: + project-name is mandatory. + +Testcase +^^^^^^^^ + +Create +"""""" + +Authentication required + +.. code-block:: shell + + testapi testcase create [-u] [username] [-p] [password] + [--project-name] [testcase-schema] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) testcase create [--project-name] [testcase-schema] + +.. NOTE:: + testcase-schema - '{"run": "", "name": "", "ci_loop": "", "tags": "", + "url": "", "catalog_description": "", "tier": "", + "dependencies": "", "version": "", "criteria": "", + "domains": "", "trust": "", "blocking": "", + "description": ""}' + + +Get +""" + +Authentication is not required + +.. code-block:: shell + + testapi testcase get [--project-name] + +.. NOTE:: + --project-name is mandatory. + +Get one +""""""" + +Authentication is not required + +.. code-block:: shell + + testapi testcase getone [--project-name] [name] + +.. NOTE:: + name and project-name are mandatory. + +Update +"""""" + +Authentication required + +.. code-block:: shell + + testapi testcase put [-u] [username] [-p] [password] [--project-name] + [name] [testcase-schema] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) testcase put [--project-name] [name] [testcase-schema] + +.. NOTE:: + testcase-schema - '{"run": "", "name": "", "ci_loop": "", "tags": "", + "url": "", "catalog_description": "", "tier": "", + "dependencies": "", "version": "", "criteria": "", + "domains": "", "trust": "", "blocking": "", + "description": ""} + + +Result +^^^^^^^ + +Create +"""""" + +Token is required. Set token as an environment variable. + +.. code-block:: shell + + testapi result create [-u] [username] [-p] [password] [result-schema] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) result create [result-schema] + +.. NOTE:: + result-schema - '{"project_name": "", "scenario": "", "stop_date": "", + "case_name": "", "build_tag": "", "version": "", + "pod_name": "", "criteria": "", "installer": "", + "start_date": "", "details": ""}' + + +Get +""" + +Authentication is not required + +.. code-block:: shell + + testapi result get [-cli-arguments] [arguments-value] + +.. NOTE:: + List of commandline arguments + + * -case : Search results using tesetcase + * -build-tag : Search results using build tag + * -from : Search results using from date + * -last : Search results using last date + * -scenario : Search results using scenario + * -period : Search results using period + * -project : Search results using project + * -to : Search results using to + * ---version : Search results using version + * -criteria : Search results using criteria + * -installer : Search results using installer + * -pod : Search results using pod + * -page : Search results using page + +Get one +""""""" + +Token is required. Set token as an environment variable. + +.. code-block:: shell + + testapi result getone [result_id] + +.. NOTE:: + result_id is mandatory. + +Deploy Result +^^^^^^^^^^^^^ + +Create +"""""" + +Token is required. Set token as an environment variable. + + +.. code-block:: shell + + testapi deployresult [-u] [username] [-p] [password] + [--project-name] [deployresult-schema] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) deployresult create [deployresult-schema] + +.. NOTE:: + deployresult-schema - '{"run": "", "name": "", "ci_loop": "", "tags": "", + "url": "", "catalog_description": "", "tier": "", + "dependencies": "", "version": "", "criteria": "", + "domains": "", "trust": "", "blocking": "", + "description": ""}' + + +Get +""" + +Authentication is not required + +.. code-block:: shell + + testapi deployresult get [-cli-arguments] [arguments-value] + +.. NOTE:: + List of command line arguments + + * -job-name : Search results using job + * -build-id : Search results using build id + * -from : Search results using from date + * -last : Search results using last date + * -scenario : Search results using scenario + * -period : Search results using period + * -to : Search results using to + * ---version : Search results using version + * -criteria : Search results using criteria + * -installer : Search results using installer + * -pod-name : Search results using pod + * -page : Search results using page + +Get one +""""""" + +Authentication is not required + +.. code-block:: shell + + testapi deployresult getone [deployresult_id] + +.. NOTE:: + deployresult_id is mandatory. + + +Scenario +^^^^^^^^ + +Create +"""""" + +Authentication required + +.. code-block:: shell + + testapi scenario create [-u] [username] [-p] [password] [scenario-schema] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) scenario create [scenario-schema] + +.. NOTE:: + scenario-schema - '{"name": "", "installers": []}' + + +Get +""" + +Authentication is not required + +.. code-block:: shell + + testapi scenario get [-name] [key-word] + +.. NOTE:: + + user can use some attributes to reduce the search results. These are not + mandatory. + + * -name : Backend will use regular expression to search. + * -project : Search using project name + * -installer : Search using installer name + * -version : Search using version name + +Get one +""""""" + +Authentication is not required + +.. code-block:: shell + + testapi scenario getone [name-keyword] + +.. NOTE:: + name-keyword is mandatory. + +Update +"""""" + +Authentication required + +.. code-block:: shell + + testapi scenario put [-u] [username] [-p] [password] [scenario-name] + [scenario-schema] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) scenario put [scenario-name] [scenario-schema] + +.. NOTE:: + scenario-schema - '{"name": "", "installers": []}' + +Delete +"""""" + +Authentication is required + +.. code-block:: shell + + testapi scenario delete [-u] [username] [-p] [password] [scenario-name] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) scenario delete [scenario-name] + +.. NOTE:: + scenario-name is mandatory. + +Scenario installer +^^^^^^^^^^^^^^^^^^ + +Create +"""""" + +Authentication required + +.. code-block:: shell + + testapi scenario installer create [-u] [username] [-p] [password] + --scenario-name [scenario-name] [installer-schema] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) scenario installer create --scenario-name [scenario-name] + [installer-schema] + +.. NOTE:: + installer-schema - '{"installer": "", "versions": []}' + +Update +"""""" + +Authentication required + +.. code-block:: shell + + testapi scenario installer put [-u] [username] [-p] [password] + --scenario-name [scenario-name] [installer-schema] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) scenario put --scenario-name [scenario-name] [installer-schema] + +.. NOTE:: + scenario-schema - '{"installer": "", "installers": []}' + +Delete +"""""" + +Authentication is required + +.. code-block:: shell + + testapi scenario delete [-u] [username] [-p] [password] --scenario-name + [scenario-name] [name] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) scenario delete --scenario-name [scenario-name] [name] + +Scenario version +^^^^^^^^^^^^^^^^ + +Create +"""""" + +Authentication required + +.. code-block:: shell + + testapi scenario version create [-u] [username] [-p] [password] + --scenario-name [scenario-name] --installer [installer] [version-schema] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) scenario installer create --scenario-name [scenario-name] + --installer [installer] [version-schema] + +.. NOTE:: + installer-schema - '{"version": "", "owner": "", "projects": []}' + +Update +"""""" + +Authentication required + +.. code-block:: shell + + testapi scenario installer put [-u] [username] [-p] [password] + --scenario-name [scenario-name] --installer [installer] [version-schema] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) scenario installer put --scenario-name [scenario-name] + --installer [installer] [installer-schema] + +.. NOTE:: + scenario-schema - '{"version": "","owner": "", "projects": []}' + +Delete +"""""" + +Authentication is required + +.. code-block:: shell + + testapi scenario installer delete [-u] [username] [-p] [password] + --scenario-name [scenario-name] --installer [installer] [name] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) scenario installer delete --scenario-name [scenario-name] + --installer [installer] [name] + +Scenario Project +^^^^^^^^^^^^^^^^ + +Create +"""""" + +Authentication required + +.. code-block:: shell + + testapi scenario project create [-u] [username] [-p] [password] + --scenario-name [scenario-name] --installer [installer] + ---version [version] [project-schema] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) scenario project create --scenario-name [scenario-name] + --installer [installer] ---version [version] [project-schema] + +.. NOTE:: + installer-schema - '{"scores": [],"customs": [], "trust_indicators": [], + project:""}' + +Update +"""""" + +Authentication required + +.. code-block:: shell + + testapi scenario project put [-u] [username] [-p] [password] + --scenario-name [scenario-name] --installer [installer] ---version + [version] [project-schema] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) scenario project put --scenario-name [scenario-name] --installer + [installer] ---version [version] [project-schema] + +.. NOTE:: + scenario-schema - '{"scores": [],"customs": [], "trust_indicators": [], + project:""}' + +Delete +"""""" + +Authentication is required + +.. code-block:: shell + + testapi scenario project delete [-u] [username] [-p] [password] + --scenario-name [scenario-name] --installer [installer] ---version + [version] [name] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) scenario project delete --scenario-name [scenario-name] + --installer [installer] ---version [version] [name] + +Scenario Customs +^^^^^^^^^^^^^^^^ + +Create +"""""" + +Authentication required + +.. code-block:: shell + + testapi scenario custom create [-u] [username] [-p] [password] + --scenario-name [scenario-name] --installer [installer] + ---version [version] --project [project] [customs] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) scenario custom create --scenario-name [scenario-name] + --installer [installer] ---version [version] --project [project] [customs] + +.. NOTE:: + + customs : Space sperated strings + +Update +"""""" + +Authentication required + +.. code-block:: shell + + testapi scenario custom put [-u] [username] [-p] [password] + --scenario-name [scenario-name] --installer [installer] ---version + [version] --project [project] [customs] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) scenario custom put --scenario-name [scenario-name] --installer + [installer] ---version [version] --project [project] [customs] + +.. NOTE:: + + customs : Space sperated strings + +Delete +"""""" + +Authentication is required + +.. code-block:: shell + + testapi scenario custom delete [-u] [username] [-p] [password] + --scenario-name [scenario-name] --installer [installer] ---version + [version] --project [project] [customs] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) scenario custom delete --scenario-name [scenario-name] + --installer [installer] ---version [version] --project [project] + [customs] + +.. NOTE:: + + customs : Space sperated strings + +Scenario Score +^^^^^^^^^^^^^^ + +Create +"""""" + +Authentication required + +.. code-block:: shell + + testapi scenario score create [-u] [username] [-p] [password] + --scenario-name [scenario-name] --installer [installer] + ---version [version] --project [project] [score_schema] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) scenario score create --scenario-name [scenario-name] + --installer [installer] ---version [version] --project [project] + [score_schema] + +.. NOTE:: + + score_schema : '{"score": "", "date": ""}' + +Scenario TrustIndicators +^^^^^^^^^^^^^^^^^^^^^^^^ + +Create +"""""" + +Authentication required + +.. code-block:: shell + + testapi scenario trustindicator create [-u] [username] [-p] [password] + --scenario-name [scenario-name] --installer [installer] + ---version [version] --project [project] [trustindicator_schema] + +or + +.. code-block:: shell + + $ testapi [-u] [username] [-p] [password] + (testapi) scenario trustindicator create --scenario-name [scenario-name] + --installer [installer] ---version [version] --project [project] + [trustindicator_schema] + +.. NOTE:: + + trustindicator_schema : '{"status": "", "date": ""}'
\ No newline at end of file diff --git a/testapi/docs/developer/devguide/web-portal.rst b/testapi/docs/developer/devguide/web-portal.rst index 62b2f17..8c4bc6c 100644 --- a/testapi/docs/developer/devguide/web-portal.rst +++ b/testapi/docs/developer/devguide/web-portal.rst @@ -6,5 +6,115 @@ Web portal ========== -.. toctree:: - :maxdepth: 2 +**Web-portal of OPNFV Testapi**: + +This project aims to provide the web interface for the Testapi framework. It uses the Restful APIs +of the testapi framework to provide front-end functionalities. + +If you are interested in how TestAPI looks like, please visit OPNFV's official `TestAPI Server`__ + +.. __: http://testresults.opnfv.org/test + +Pre-requsites +============= + +In the web portal, we are using AngularJS(1.3.15) as the frontend framework with Bootstrap(v3) CSS. + +Running locally +=============== + +Installation +^^^^^^^^^^^^ + +Web portal will be installed with the testapi framework. No extra installation. + +.. code-block:: shell + + python setup.py install + +Start Server +^^^^^^^^^^^^ + +.. code-block:: shell + + *opnfv-testapi [--config-file <config.ini>]* + +If --config-file is provided, the specified configuration file will be employed +when starting the server, or else /etc/opnfv_testapi/config.ini will be utilized +by default. + +After executing the command successfully, a TestAPI server will be started on +port 8000, to visit web portal, please access http://hostname:8000 + +Test +=============== + +There are few external requirements for the testing. +They are + +1. npm : node package manager + you can get the installation package for nodejs from the official `website`__ + + .. __: https://nodejs.org/en/ + +2. grunt cli : Automation tool + +.. code-block:: shell + + npm install -g grunt-cli + +After installing global dependencies, you have to install the required local node modules. + +.. code-block:: shell + + npm install + +**Running tests** + +.. code-block:: shell + + grunt e2e + +Authentication +============== + +The web portal is using Linux identity server as the Central Authentication Service. The following +diagram will explain the authentication process. + +.. image:: /images/CAS-sequence.jpg + :width: 600 + :alt: Workflow of the Athentication + +When a new user initially logs into an application they won't have established a +session with the application. Instead of displaying a login form asking for the username and +password, the application (via the CAS Client) will redirect the browser to the linux foundation +login page. Linux foundation identity server then authenticates the user. If the authentication +fails, the Linux foundation login page is displayed again with an error message. So until +authentication succeeds, the user will not be returned to the application. + +Authorization +============= + +TestAPI has 3 level authorization layer. They are + +**Public** + +The public can view the resources(pod, project, testcase, result, deploy result, scenario). +They do not have the access to create, delete or modify the resources. + +**User - Contributors** + +Contributors level user can view all the resources(pod, project, testcase, result, deploy result, +scenario). They can create/delete/modify pod and scenario. + +They do not have the access to create project or testcase. + +**User - Submitter** + +Submitter level user can view all the resources(pod, project, testcase, result, deploy result, +scenario). They can create/delete/modify pod and scenario. + +If user want to create/modify/delete a project or testcase then user has to be in the Submitter +group for that specific project. + +Currently, we can't create/modify/delete results or deploy results from the web portal.
\ No newline at end of file diff --git a/testapi/docs/internship/webportal.rst b/testapi/docs/internship/webportal.rst new file mode 100644 index 0000000..1ea9c19 --- /dev/null +++ b/testapi/docs/internship/webportal.rst @@ -0,0 +1,169 @@ +.. This work is licensed under a Creative Commons Attribution 4.0 International License. +.. http://creativecommons.org/licenses/by/4.0 + + +***************************** +Web Portal for OPNFV Test API +***************************** + +Author: Tharmarajasingam Thuvarakan Mentors: S. Feng, J.Lausuch, M.Richomme + +Abstract +======== + +TestAPI is used by all the test projects to report results. It is also used to declare projects, +test cases and labs. It is defined in the Functest developer guide. The internship aims to add web +portal for TestAPI. The showcase user got through the web portal, will be more human-friendly +compared to the swagger page. Also, internship aims to build a python client to reduce the workload. +Python client can be used as a python module. + +Overview +======== + +The internship time period was from Oct 9th to May 18th. The project proposal page is here [1]_. +The intern project was assigned to Thuvarakan and was mentored by S. Feng, J.Lausuch, M.Richomme. +The link to the patches submitted is [2]_. The internship was successfully completed and the +documentation is as follows. + + + +Problem Statement +================= + +The following were to be accomplished within the internship time frame. + +* Redesign the website theme + + Change the existing theme of the frontend and design a unified theme. + +* Add separate pages to each resource + + Create a separate web page for each resource in the new theme. + +* Implement all the functionalities in the frontend + + Implement the backend functionalities in the frontend for each + resource. + +* Authentication for testapiclient + + Implement the authentication functionality in the testapiclient. + +* Add all functionalities to testapiclient + + Implement the backend functionalities in the testapiclient for each + resource. + +* Add support to testapiclient as a python module + + Convert the testapiclient from CLI only to CLI and python module + mode. + + +Curation Phase +============== + +The curation phase was the first 4 to 8 weeks of the internship. This phase +was to get familiar with the testapi code and functionality and propose the +solutions/tools for the tasks mentioned above. + +These are the tools, we proposed for the solutions. + +* protractor: An end-to-end test framework for Angular and AngularJS applications + +* grunt: A Javascript task runner, a tool used to automatically perform + frequent tasks such as minification, compilation, unit testing, and + linting. + +* cliff: Command Line Interface Formulation Framework. + + +Schedule +======== + +=================== ======================================================== + Date Comment +=================== ======================================================== +10th Oct ~17th Oct Setting up the development environment, design decisions +17th Oct ~ 24th Oct Pod web portal CRUD +24th Oct ~ 31st Oct Projects web portal CRUD +13st Oct ~ 7th Nov Test cases web portal CRUD +7th Nov ~ 14th Nov Results web portal R +14th Nov ~ 21st Nov Results web portal R +21st Nov ~ 28th Nov Scenario web portal CRUD +28th Nov ~ 5th Dec Testapi-client framework +5th Dec ~ 12nd Dec Pods testapi-client CRUD +12nd Dec ~ 19th Dec Projects testapi-client CRUD +19th Dec ~ 26th Dec Test cases testapi-client CRUD +26th Dec ~ 9th Jan Results testapi-client CRUD +9th Jan ~ 23rd Jan Scenario testapi-client CRUD +23rd Jan ~ 6th Mar Bugfix in the frontend and testapiclient +6th Mar ~ 20th Mar Convert testapiclient to python module +20th Mar ~ 3rd Apr Testing the python module +3rd Apr ~ 9th May Documentation & Bugfix +=================== ======================================================== + + +FAQ +=== + + +Frontend +******** + +1. How to add a new test file for the frontend? + + * Frontend test is handled by protractor [3]_ and + automated by the grunt [4]_. All the tests are located in + "opnfv_testapi/tests/UI/e2e". + First, create a text file in the e2e folder. Then add it to the spec + list in the "opnfv_testapi/ui/Gruntfile.js". + + +2. How to test application's functionalities interactively? + + * Application requires authentication for many functionalities. + It will cause time for the developer to check the functionalities. + Developers can use the application in the authentication false mode. + To do that, first, change the authenticate to false in the + "etc/config.ini" file then change the authenticate to false in + the "opnfv_testapi/ui/config.json" file. + + +3. Browser does not reflect the code changes, what is it mean? + + * Browser is saving the caches for fast reloadings. Sometime browser + won't reload the new changes, to solve that we have to clear the browser + caches. + + +Testapiclient +************* + +1. How to add a new test file for testapiclient? + + * Frontend test is handled by testtools [5]_ and automated by tox [6]_. + All the tests are located in "testapi-client/tests/unit". Create a text + file in the unit folder. The name of the test file should start with + 'test\_'. It will automatically add that test file to queue. + + +2. Difference between client and cli? + + * Client is used to importing testapiclient as a python module. + The cli folder contained the command line interface for the testapiclient. + +References +========== + +.. [1] https://wiki.opnfv.org/display/DEV/Intern+Project%3A+Web+Portal+for+OPNFV+Test+API + +.. [2] https://gerrit.opnfv.org/gerrit/#/q/status:merged+owner:%22Thuvarakan+Tharmarajasingam+%253Ctharma.thuva%2540gmail.com%253E%22 + +.. [3] https://www.protractortest.org/ + +.. [4] https://gruntjs.com + +.. [5] https://github.com/testing-cabal/testtools + +.. [6] https://tox.readthedocs.io/en/latest/#
\ No newline at end of file diff --git a/testapi/opnfv_testapi/common/check.py b/testapi/opnfv_testapi/common/check.py index 09a9270..fdc527f 100644 --- a/testapi/opnfv_testapi/common/check.py +++ b/testapi/opnfv_testapi/common/check.py @@ -65,12 +65,14 @@ def is_reource_tied(method): } if self.table in tied_maps: if method.__name__ == '_update': - if 'name' not in self.json_args: - ret = yield gen.coroutine(method)(self, *args, **kwargs) - raise gen.Return(ret) + if 'name' in self.json_args: + if self.json_args['name'] == kwargs.get('query')['name']: + ret = yield gen.coroutine(method)( + self, *args, **kwargs) + raise gen.Return(ret) query_data[tied_maps[self.table][1]] = kwargs.get('query')['name'] - data = yield dbapi.db_find_one(tied_maps[self.table][0], - query_data) + data = yield dbapi.db_find_one( + tied_maps[self.table][0], query_data) if data: raises.Unauthorized(message.tied_with_resource()) ret = yield gen.coroutine(method)(self, *args, **kwargs) diff --git a/testapi/opnfv_testapi/tests/UI/e2e/authenticateFalseSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/authenticateFalseSpec.js index e287f29..6b9a2bf 100644 --- a/testapi/opnfv_testapi/tests/UI/e2e/authenticateFalseSpec.js +++ b/testapi/opnfv_testapi/tests/UI/e2e/authenticateFalseSpec.js @@ -250,7 +250,7 @@ describe('testing the scenarios page for anonymous user', function () { browser.get(baseURL+"#/scenarios/test-scenario"); var EC = browser.ExpectedConditions; browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); - var buttonAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[2]/button')) + var buttonAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[2]/button')) expect(buttonAdd.isDisplayed()).toBe(true); }); @@ -258,9 +258,9 @@ describe('testing the scenarios page for anonymous user', function () { browser.get(baseURL+"#/scenarios/test-scenario"); var EC = browser.ExpectedConditions; browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); - var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[1]/a/p')) installersShow.click(); - var installerDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[3]/button')) + var installerDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[1]/td[3]/button')) expect(installerDelete.isDisplayed()).toBe(true); }); @@ -268,11 +268,11 @@ describe('testing the scenarios page for anonymous user', function () { browser.get(baseURL+"#/scenarios/test-scenario"); var EC = browser.ExpectedConditions; browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); - var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[1]/a/p')) installersShow.click(); - var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) installerShow.click(); - var versionAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[2]/button')) + var versionAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[2]/button')) versionAdd.click() expect(versionAdd.isDisplayed()).toBe(true); }); @@ -281,15 +281,15 @@ describe('testing the scenarios page for anonymous user', function () { browser.get(baseURL+"#/scenarios/test-scenario"); var EC = browser.ExpectedConditions; browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); - var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[1]/a/p')) installersShow.click(); - var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) installerShow.click(); - var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) versionsShow.click(); - var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) versionShow.click() - var versionDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody[1]/tr[1]/td[3]/button')) + var versionDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody[1]/tr[1]/td[3]/button')) expect(versionDelete.isDisplayed()).toBe(true); }); @@ -297,15 +297,15 @@ describe('testing the scenarios page for anonymous user', function () { browser.get(baseURL+"#/scenarios/test-scenario"); var EC = browser.ExpectedConditions; browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); - var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[1]/a/p')) installersShow.click(); - var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) installerShow.click(); - var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) versionsShow.click(); - var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) versionShow.click() - var projectAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[2]/button')) + var projectAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[2]/button')) projectAdd.click() expect(projectAdd.isDisplayed()).toBe(true); }); @@ -314,17 +314,17 @@ describe('testing the scenarios page for anonymous user', function () { browser.get(baseURL+"#/scenarios/test-scenario"); var EC = browser.ExpectedConditions; browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); - var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[1]/a/p')) installersShow.click(); - var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) installerShow.click(); - var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) versionsShow.click(); - var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) versionShow.click() - var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) + var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) projectsShow.click(); - var projectDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[1]/td[3]/button')) + var projectDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[1]/td[3]/button')) projectDelete.click() expect(projectDelete.isDisplayed()).toBe(true); }); @@ -333,24 +333,24 @@ describe('testing the scenarios page for anonymous user', function () { browser.get(baseURL+"#/scenarios/test-scenario"); var EC = browser.ExpectedConditions; browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); - var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[1]/a/p')) installersShow.click(); - var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) installerShow.click(); - var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) versionsShow.click(); - var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) versionShow.click() - var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) + var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) projectsShow.click(); - var projectShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + var projectShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) projectShow.click(); - var customsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/a/p')) + var customsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/a/p')) customsShow.click(); var row = element.all(by.repeater('(indexCU, custom) in project.customs')).first(); var cells = row.all(by.tagName('td')); expect(cells.get(0).getText()).toContain("dvs"); - var buttonAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/button')) + var buttonAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/button')) buttonAdd.click() expect(buttonAdd.isDisplayed()).toBe(true); }); @@ -359,24 +359,24 @@ describe('testing the scenarios page for anonymous user', function () { browser.get(baseURL+"#/scenarios/test-scenario"); var EC = browser.ExpectedConditions; browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); - var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[1]/a/p')) installersShow.click(); - var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) installerShow.click(); - var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) versionsShow.click(); - var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) versionShow.click() - var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) + var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) projectsShow.click(); - var projectShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + var projectShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) projectShow.click(); - var customsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/a/p')) + var customsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/a/p')) customsShow.click(); var row = element.all(by.repeater('(indexCU, custom) in project.customs')).first(); var cells = row.all(by.tagName('td')); expect(cells.get(0).getText()).toContain("dvs"); - var buttonDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/table/tbody/tr[1]/td[2]/button')) + var buttonDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/table/tbody/tr[1]/td[2]/button')) buttonDelete.click() expect(buttonDelete.isDisplayed()).toBe(true); }); diff --git a/testapi/opnfv_testapi/tests/UI/e2e/deployResultsControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/deployResultsControllerSpec.js index e00243b..40f60e4 100644 --- a/testapi/opnfv_testapi/tests/UI/e2e/deployResultsControllerSpec.js +++ b/testapi/opnfv_testapi/tests/UI/e2e/deployResultsControllerSpec.js @@ -383,7 +383,7 @@ describe('testing the result page for user', function () { buttonClear.click(); var row = element.all(by.repeater('(index, result) in ctrl.data.deployresults')).first(); var cells = row.all(by.tagName('td')); - expect(cells.get(0).getText()).toContain("3c9f8d62"); + expect(cells.get(0).getText()).toContain("3c9f8d63"); }); it('view the deploy results ', function () { diff --git a/testapi/opnfv_testapi/tests/UI/e2e/podsControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/podsControllerSpec.js index 16b219d..ac1f954 100644 --- a/testapi/opnfv_testapi/tests/UI/e2e/podsControllerSpec.js +++ b/testapi/opnfv_testapi/tests/UI/e2e/podsControllerSpec.js @@ -78,7 +78,7 @@ describe('testing the Pods page for anonymous user', function () { it('Sort the results by mode', function () { browser.get(baseURL+'#/pods'); - var sortMode = element(by.xpath('//*[@id="ng-app"]/body/div/div[6]/div/table/thead/tr/th[4]/a[2]/span')) + var sortMode = element(by.xpath('//*[@id="ng-app"]/body/div/div[5]/div/table/thead/tr/th[4]/a[2]/span')) sortMode.click(); var row = element.all(by.repeater('(index, pod) in ctrl.data.pods')).first(); var cells = row.all(by.tagName('td')); @@ -87,7 +87,7 @@ describe('testing the Pods page for anonymous user', function () { it('Sort the results by role', function () { browser.get(baseURL+'#/pods'); - var sortRole = element(by.xpath('//*[@id="ng-app"]/body/div/div[6]/div/table/thead/tr/th[3]/a[2]/span')) + var sortRole = element(by.xpath('//*[@id="ng-app"]/body/div/div[5]/div/table/thead/tr/th[3]/a[2]/span')) sortRole.click(); var row = element.all(by.repeater('(index, pod) in ctrl.data.pods')).first(); var cells = row.all(by.tagName('td')); @@ -262,8 +262,11 @@ describe('testing the Pods page for authorized user', function () { .isDisplayed()).toBe(true); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Delete Success")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Delete Success")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('Delete the pods ', function () { @@ -272,8 +275,11 @@ describe('testing the Pods page for authorized user', function () { deleteOperation.click(); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Delete Success")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Delete Success")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('Create the pod', function () { @@ -286,8 +292,11 @@ describe('testing the Pods page for authorized user', function () { name.sendKeys('test1'); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Create Success")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Create Success")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('Showing error when creating with a empty name ', function () { @@ -299,8 +308,11 @@ describe('testing the Pods page for authorized user', function () { browser.wait(EC.visibilityOf(name), 5000); var buttonOK = element(by.buttonText('Ok')); buttonOK.click() - expect(element(by.cssContainingText(".alert","Name is missing.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".error.show","Name is missing.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('cancel the delete confimation modal of the pod ', function () { @@ -356,8 +368,11 @@ describe('testing the Pods page for authorized user', function () { deleteOperation.click(); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.css(".alert.alert-danger")) + browser.ignoreSynchronization = true; + expect(element(by.css(".error.show")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('view the test case ', function () { @@ -394,8 +409,13 @@ describe('testing the Pods page for authorized user', function () { }, ]); browser.get(baseURL+"#/pods"); - expect(element(by.css(".alert.alert-danger")) + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '/#/pods'), 5000); + browser.ignoreSynchronization = true; + expect(element(by.css(".error.show")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); });
\ No newline at end of file diff --git a/testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js index 1117ef5..da86389 100644 --- a/testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js +++ b/testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js @@ -324,8 +324,12 @@ describe('testing the Project Link for user who is in submitter group', function name.sendKeys('testproject'); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Project is successfully created.")) + + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Project is successfully created.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('Show error if user doesnt have permission to Create the Project', function () { @@ -340,7 +344,10 @@ describe('testing the Project Link for user who is in submitter group', function description.sendKeys('demoDescription'); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.css(".alert.alert-danger")).isDisplayed()).toBe(true); + browser.ignoreSynchronization = true; + expect(element(by.css(".error")).isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('Showing error when creating with a empty name ', function () { @@ -352,8 +359,11 @@ describe('testing the Project Link for user who is in submitter group', function browser.wait(EC.visibilityOf(name), 5000); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); + browser.ignoreSynchronization = true; expect(element(by.cssContainingText(".alert","Name is missing.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('Show error when user click the create button with an already existing name', function () { @@ -368,7 +378,10 @@ describe('testing the Project Link for user who is in submitter group', function description.sendKeys('demoDescription'); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.css(".alert.alert-danger")).isDisplayed()).toBe(true); + browser.ignoreSynchronization = true; + expect(element(by.css(".error")).isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('cancel the delete confimation modal of the project ', function () { @@ -388,8 +401,11 @@ describe('testing the Project Link for user who is in submitter group', function .isDisplayed()).toBe(true); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Projects is successfully deleted")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Projects is successfully deleted")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it(' Show error if user doesnt has permission to delete the projects ', function () { @@ -442,7 +458,10 @@ describe('testing the Project Link for user who is in submitter group', function deleteOperation.click(); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.css(".alert.alert-danger")).isDisplayed()).toBe(true); + browser.ignoreSynchronization = true; + expect(element(by.css(".error")).isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('cancel the Edit modal of the Project ', function () { @@ -468,8 +487,12 @@ describe('testing the Project Link for user who is in submitter group', function name.sendKeys('test1'); var buttonOK = element(by.buttonText('Ok')); buttonOK.click() - expect(element(by.cssContainingText(".alert","Project is successfully updated.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Project is successfully updated.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; + }); it('Show error if user doesnt has permission to edit the projects ', function () { @@ -526,7 +549,10 @@ describe('testing the Project Link for user who is in submitter group', function name.sendKeys('test1'); var buttonOK = element(by.buttonText('Ok')); buttonOK.click() - expect(element(by.css(".alert.alert-danger")).isDisplayed()).toBe(true); + browser.ignoreSynchronization = true; + expect(element(by.css(".error")).isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('Batch Delete the projects ', function () { @@ -537,8 +563,12 @@ describe('testing the Project Link for user who is in submitter group', function buttonDelete.click(); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Projects is successfully deleted")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Projects is successfully deleted")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; + }); it('If backend is not responding then show error when user click the create button',function(){ @@ -570,8 +600,10 @@ describe('testing the Project Link for user who is in submitter group', function name.sendKeys('testproject'); details.sendKeys('demoDescription'); var buttonOK = element(by.buttonText('Ok')); - buttonOK.click().then(function(){ - expect(element(by.css(".alert.alert-danger")).isDisplayed()).toBe(true); - }); + buttonOK.click() + browser.ignoreSynchronization = true; + expect(element(by.css(".error")).isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); }) diff --git a/testapi/opnfv_testapi/tests/UI/e2e/resultsControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/resultsControllerSpec.js index 925e82c..48690a1 100644 --- a/testapi/opnfv_testapi/tests/UI/e2e/resultsControllerSpec.js +++ b/testapi/opnfv_testapi/tests/UI/e2e/resultsControllerSpec.js @@ -198,8 +198,8 @@ describe('testing the result page for anonymous user', function () { browser.wait(EC.urlContains(baseURL+ '#/results'), 10000); var resultLink = element(by.linkText('0e2643f4')).click(); browser.wait(EC.urlContains(baseURL+ '#/result/5a45170bbb2092000e2643f4'), 10000); - expect(element(by.cssContainingText(".key.col-md-1","failures")).isDisplayed()).toBe(true); - expect(element(by.cssContainingText(".leaf-value.col-md-11","0")).isDisplayed()).toBe(true); + expect(element(by.cssContainingText(".key.col-md-2","failures")).isDisplayed()).toBe(true); + expect(element(by.cssContainingText(".leaf-value.col-md-10","0")).isDisplayed()).toBe(true); }); it('Should show the results in results page related to the filters', function () { diff --git a/testapi/opnfv_testapi/tests/UI/e2e/scenarioControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/scenarioControllerSpec.js index 7777721..37b42dc 100644 --- a/testapi/opnfv_testapi/tests/UI/e2e/scenarioControllerSpec.js +++ b/testapi/opnfv_testapi/tests/UI/e2e/scenarioControllerSpec.js @@ -682,8 +682,11 @@ describe('testing the scenarios page for user', function () { name.sendKeys('test'); var buttonOk = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[2]/button[1]')) buttonOk.click() - expect(element(by.cssContainingText(".alert","Installers are successfully updated.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Installers are successfully updated.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); @@ -720,8 +723,11 @@ describe('testing the scenarios page for user', function () { .isDisplayed()).toBe(true); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Installer is successfully deleted.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Installer is successfully deleted.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it( 'Expand installer by user', function() { @@ -753,8 +759,11 @@ describe('testing the scenarios page for user', function () { owner.sendKeys('testOwner'); var buttonOk = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[2]/button[1]')) buttonOk.click() - expect(element(by.cssContainingText(".alert","Versions are successfully updated.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Versions are successfully updated.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it( 'Expand versions by user', function() { @@ -793,8 +802,11 @@ describe('testing the scenarios page for user', function () { .isDisplayed()).toBe(true); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Versions are successfully deleted.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Versions are successfully deleted.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it( 'Expand version by user', function() { @@ -832,8 +844,11 @@ describe('testing the scenarios page for user', function () { project.sendKeys('testP'); var buttonOk = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[2]/button[1]')) buttonOk.click() - expect(element(by.cssContainingText(".alert","Projects are successfully updated.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Projects are successfully updated.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it( 'Expand projects by user', function() { @@ -878,8 +893,11 @@ describe('testing the scenarios page for user', function () { .isDisplayed()).toBe(true); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Projects are successfully Deleted.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Projects are successfully Deleted.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it( 'Expand project by user', function() { @@ -1011,8 +1029,11 @@ describe('testing the scenarios page for user', function () { custom.sendKeys('testC'); var buttonOk = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[2]/button[1]')) buttonOk.click() - expect(element(by.cssContainingText(".alert","Customs are successfully updated.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Customs are successfully updated.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it( 'Add multiple Customs by user', function() { @@ -1043,8 +1064,11 @@ describe('testing the scenarios page for user', function () { custom.sendKeys('testC,testD,'); var buttonOk = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[2]/button[1]')) buttonOk.click() - expect(element(by.cssContainingText(".alert","Customs are successfully updated.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Customs are successfully updated.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it( 'Delete Customs by user', function() { @@ -1074,8 +1098,11 @@ describe('testing the scenarios page for user', function () { .isDisplayed()).toBe(true); var buttonOk = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div[3]/button[1]')) buttonOk.click() - expect(element(by.cssContainingText(".alert","Customs are successfully deleted.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Customs are successfully deleted.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); });
\ No newline at end of file diff --git a/testapi/opnfv_testapi/tests/UI/e2e/scenariosControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/scenariosControllerSpec.js index e7c5fb0..55922ad 100644 --- a/testapi/opnfv_testapi/tests/UI/e2e/scenariosControllerSpec.js +++ b/testapi/opnfv_testapi/tests/UI/e2e/scenariosControllerSpec.js @@ -119,7 +119,7 @@ describe('testing the scenarios page for anonymous user', function () { it('Sort scenarios', function () { browser.get(baseURL+"#/scenarios"); - var sort = element(by.xpath('//*[@id="ng-app"]/body/div/div[4]/div/table/thead/tr/th[2]/a[2]/span')) + var sort = element(by.xpath('//*[@id="ng-app"]/body/div/div[5]/div/table/thead/tr/th[2]/a[2]/span')) sort.click(); var row = element.all(by.repeater('(index, scenario) in ctrl.data.scenarios')).first(); var cells = row.all(by.tagName('td')); @@ -284,8 +284,11 @@ describe('testing the scenarios page for user', function () { name.sendKeys('test'); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Scenario is successfully created.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Scenario is successfully created.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('create scenarrio by user with installers ', function () { @@ -304,8 +307,11 @@ describe('testing the scenarios page for user', function () { buttonOK.click(); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Scenario is successfully created.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Scenario is successfully created.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('create scenarrio by user with installers with versions ', function () { @@ -333,8 +339,11 @@ describe('testing the scenarios page for user', function () { buttonOK.click(); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Scenario is successfully created.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Scenario is successfully created.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('create scenarrio by user with installers with versions with project', function () { @@ -369,8 +378,11 @@ describe('testing the scenarios page for user', function () { buttonOK.click(); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Scenario is successfully created.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Scenario is successfully created.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('create scenarrio by user with installers with versions with project with custom', function () { @@ -412,8 +424,11 @@ describe('testing the scenarios page for user', function () { buttonOK.click(); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Scenario is successfully created.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Scenario is successfully created.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('view scenarrio by user ', function () { @@ -443,8 +458,11 @@ describe('testing the scenarios page for user', function () { .isDisplayed()).toBe(true); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Scenario is successfully deleted.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Scenario is successfully deleted.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('Batch Delete the scenarios ', function () { @@ -455,8 +473,11 @@ describe('testing the scenarios page for user', function () { buttonDelete.click(); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Scenario is successfully deleted.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Scenario is successfully deleted.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('Edit the scenarios ', function () { @@ -469,8 +490,11 @@ describe('testing the scenarios page for user', function () { name.sendKeys('test2'); var buttonOK = element(by.buttonText('Ok')); buttonOK.click() - expect(element(by.cssContainingText(".alert","Scenario is successfully Updated.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Scenario is successfully Updated.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); });
\ No newline at end of file diff --git a/testapi/opnfv_testapi/tests/UI/e2e/testCasesControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/testCasesControllerSpec.js index 53e7bdf..38e0f24 100644 --- a/testapi/opnfv_testapi/tests/UI/e2e/testCasesControllerSpec.js +++ b/testapi/opnfv_testapi/tests/UI/e2e/testCasesControllerSpec.js @@ -550,8 +550,11 @@ describe('testing the test cases page for user who is in submitter group', funct name.sendKeys('test'); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Testcase is successfully created.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Testcase is successfully created.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('Showing error when creating with a empty name ', function () { @@ -565,8 +568,11 @@ describe('testing the test cases page for user who is in submitter group', funct browser.wait(EC.visibilityOf(name), 5000); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Name is missing.")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".error.show","Name is missing.")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('cancel the delete confimation modal of the test case ', function () { @@ -590,8 +596,11 @@ describe('testing the test cases page for user who is in submitter group', funct deleteOperation.click(); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Test case is successfully deleted")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Test case is successfully deleted")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('cancel the Edit modal of the test case ', function () { @@ -621,8 +630,11 @@ describe('testing the test cases page for user who is in submitter group', funct name.sendKeys('test1'); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Test case is successfully updated")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Test case is successfully updated")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); it('view the test case ', function () { @@ -646,7 +658,10 @@ describe('testing the test cases page for user who is in submitter group', funct buttonDelete.click(); var buttonOK = element(by.buttonText('Ok')); buttonOK.click(); - expect(element(by.cssContainingText(".alert","Test case is successfully deleted")) + browser.ignoreSynchronization = true; + expect(element(by.cssContainingText(".success.show","Test case is successfully deleted")) .isDisplayed()).toBe(true); + browser.sleep(500); + browser.ignoreSynchronization = false; }); }) diff --git a/testapi/opnfv_testapi/ui/Gruntfile.js b/testapi/opnfv_testapi/ui/Gruntfile.js index 805ad9f..ab59475 100644 --- a/testapi/opnfv_testapi/ui/Gruntfile.js +++ b/testapi/opnfv_testapi/ui/Gruntfile.js @@ -6,7 +6,22 @@ module.exports = function (grunt) { grunt.loadNpmTasks('grunt-wait'); grunt.loadNpmTasks('grunt-contrib-copy'); grunt.loadNpmTasks('grunt-contrib-connect'); + grunt.loadNpmTasks('grunt-convert'); grunt.initConfig({ + convert: { + options: { + explicitArray: false, + }, + json2xml: { + options: { + xml: { + header: true + } + }, + src: ['../tests/UI/coverage/coverage.json'], + dest: '../tests/UI/coverage/coverage.xml' + } + }, connect: { server: { options: { @@ -159,6 +174,7 @@ module.exports = function (grunt) { 'wait:default', 'protractor_coverage', 'makeReport', + 'convert', 'shell:deleteFiles' ]); } diff --git a/testapi/opnfv_testapi/ui/components/pods/pods.html b/testapi/opnfv_testapi/ui/components/pods/pods.html index 8e66a9c..b5dadf5 100644 --- a/testapi/opnfv_testapi/ui/components/pods/pods.html +++ b/testapi/opnfv_testapi/ui/components/pods/pods.html @@ -19,22 +19,18 @@ <div class="col-sm-1 pull-right"> <button type="button" class="btn btn-success" ng-click="ctrl.listPods()"> <i class="fa fa-search"></i> Filter</button> + <div ng-class="{'show': ctrl.showError}" id="toast" class="error"> + <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true" ></span> + {{ctrl.error}}</div> + <div ng-class="{'show': ctrl.showSuccess}" id="toast" class="success"> + <span class="glyphicon glyphicon-ok" aria-hidden="true"></span> + {{ctrl.success}}</div> </div> <div class="col-sm-3 pull-right"> <span style="margin-top:6px">Search: </span> <input type="text" class="form-control search" ng-enter="ctrl.listPods()" ng-Model="ctrl.filterText" placeholder="Search String"> </div> </div> -<div class="col-md-12"> - <div ng-show="ctrl.showError" class="col-md-12 alert alert-danger" role="alert"> - <span class="pull-right"> {{ctrl.error}}</span> - <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> - </div> - <div ng-show="ctrl.showSuccess" class="col-md-12 alert alert-success" role="alert"> - <span class="pull-right"> {{ctrl.success}}</span> - <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span> - </div> -</div> <div class="col-md-12" style="padding-right:0px"> <div class="table-responsive"> <table class="table table-bordered table-hover" ng-data="ctrl.data.pods"> diff --git a/testapi/opnfv_testapi/ui/components/pods/podsController.js b/testapi/opnfv_testapi/ui/components/pods/podsController.js index c50fa5a..3b6ab97 100644 --- a/testapi/opnfv_testapi/ui/components/pods/podsController.js +++ b/testapi/opnfv_testapi/ui/components/pods/podsController.js @@ -21,7 +21,7 @@ PodsController.$inject = [ '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert', - 'confirmModal', 'keepState', 'sortService' + 'confirmModal', 'keepState', 'sortService', '$timeout' ]; /** @@ -30,7 +30,7 @@ * through pods declared in TestAPI. */ function PodsController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl, - raiseAlert, confirmModal, keepState, sortService) { + raiseAlert, confirmModal, keepState, sortService, $timeout) { var ctrl = this; ctrl.url = testapiApiUrl + '/pods'; ctrl.checkBox = [] @@ -48,6 +48,18 @@ ctrl.batchDelete = batchDelete; ctrl.viewPod = viewPod ctrl.sortBy = sortBy + ctrl.toastError = toastError + ctrl.toastSuccess = toastSuccess + + function toastError() { + ctrl.showError = true + $timeout(function(){ ctrl.showError = false;}, 3000); + } + + function toastSuccess() { + ctrl.showSuccess = true + $timeout(function(){ ctrl.showSuccess = false;}, 3000); + } function sortBy(field){ ctrl.data.pods = sortService.sortFunction(ctrl.data.pods, field , ctrl.sorting[field] ) @@ -82,19 +94,21 @@ role: pod.role, details: pod.details }; - ctrl.podsRequest = - $http.post(pods_url, body).success(function (data) { - ctrl.showSuccess = true ; + ctrl.podsRequest = $http.post(pods_url, body) + + ctrl.podsRequest.success(function (data) { ctrl.success = "Create Success" + ctrl.toastSuccess() ctrl.listPods(); }).catch(function (data) { - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError() }); + return ctrl.podsRequest } else{ - ctrl.showError = true; ctrl.error = 'Name is missing.' + ctrl.toastError() } } @@ -124,8 +138,8 @@ } }).catch(function (data) { ctrl.data = null; - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError() }); } @@ -139,12 +153,12 @@ function podDelete(podName){ var pods_url = ctrl.url + "/" + podName $http.delete(pods_url).success(function(){ - ctrl.showSuccess = true ; ctrl.success = "Delete Success" + ctrl.toastSuccess() ctrl.listPods(); }).catch(function (data) { - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError() }); } @@ -247,9 +261,10 @@ * inputs. */ function confirm() { - $uibModalInstance.close(); if (angular.isDefined(ctrl.data.successHandler)) { - ctrl.data.successHandler(ctrl.pod); + ctrl.data.successHandler(ctrl.pod).success( function(data){ + $uibModalInstance.close(); + }) } } diff --git a/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCases.html b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCases.html index 395db03..04baa9c 100644 --- a/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCases.html +++ b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCases.html @@ -11,16 +11,12 @@ <i class="fa fa-plus"></i> Create</button> </div> </div> - <div class='clo-md-12'> - <div ng-show="testCasesCtrl.showError" class="alert alert-danger" role="alert"> - <span class="pull-right"> {{testCasesCtrl.error}}</span> - <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> - </div> - <div ng-show="testCasesCtrl.showSuccess" class="alert alert-success" role="alert"> - <span class="pull-right"> {{testCasesCtrl.successMessage}}</span> - <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span> - </div> - </div> + <div ng-class="{'show': testCasesCtrl.showError}" id="toast" class="error"> + <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true" ></span> + {{testCasesCtrl.error}}</div> + <div ng-class="{'show': testCasesCtrl.showSuccess}" id="toast" class="success"> + <span class="glyphicon glyphicon-ok" aria-hidden="true"></span> + {{testCasesCtrl.success}}</div> <div class='clo-md-12' style="padding-right:0px"> <div class="table-responsive"> <table class="table table-bordered table-hover" ng-data="testCasesCtrl.data.testcases"> diff --git a/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCasesController.js b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCasesController.js index 4d6153e..ea0498a 100644 --- a/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCasesController.js +++ b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCasesController.js @@ -21,7 +21,7 @@ TestCasesController.$inject = [ '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert', - 'confirmModal', 'authenticate' + 'confirmModal', 'authenticate', '$timeout' ]; /** @@ -31,7 +31,7 @@ * in them. */ function TestCasesController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl, - raiseAlert, confirmModal, authenticate) { + raiseAlert, confirmModal, authenticate, $timeout) { var ctrl = this; ctrl.loadDetails = loadDetails; ctrl.name = $state.params['name']; @@ -49,29 +49,40 @@ ctrl.checkBox = []; ctrl.checkBoxList = []; + ctrl.toastError = toastError + ctrl.toastSuccess = toastSuccess + + function toastError() { + ctrl.showError = true + $timeout(function(){ ctrl.showError = false;}, 3000); + } + + function toastSuccess() { + ctrl.showSuccess = true + $timeout(function(){ ctrl.showSuccess = false;}, 3000); + } /** * This will contact the TestAPI to create a new test case. */ function createTestCase(name, testcase) { - ctrl.showError = false; - ctrl.showSuccess = false; if(testcase.name != "" && testcase.name!=null){ var testCase_url = ctrl.requestUrl; - ctrl.testCasesRequest = - $http.post(testCase_url, testcase).success(function (data){ - ctrl.showSuccess = true ; - ctrl.successMessage = "Testcase is successfully created." + ctrl.testCasesRequest = $http.post(testCase_url, testcase) + ctrl.testCasesRequest.success(function (data){ + ctrl.success = "Testcase is successfully created." loadDetails(); + ctrl.toastSuccess() }) .catch(function (data) { - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError(); }); + return ctrl.testCasesRequest; } else{ - ctrl.showError = true; ctrl.error = 'Name is missing.' + ctrl.toastError(); } } @@ -114,24 +125,23 @@ * This will contact the TestAPI to update an existing test case. */ function updateTestCase(name, testCase) { - ctrl.showError = false; - ctrl.showSuccess = false; if(testCase.name != ""){ var testCase_url = ctrl.requestUrl + '/' + name; - ctrl.testCasesRequest = - $http.put(testCase_url, testCase).success(function (data){ - ctrl.showSuccess = true ; - ctrl.successMessage = "Test case is successfully updated" + ctrl.testCasesRequest = $http.put(testCase_url, testCase) + ctrl.testCasesRequest.success(function (data){ + ctrl.success = "Test case is successfully updated" loadDetails(); + ctrl.toastSuccess(); }) .catch(function (data) { - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError() }); + return ctrl.testCasesRequest; } else{ - ctrl.showError = true; ctrl.error = 'Name is missing.' + ctrl.toastError() } } @@ -139,16 +149,14 @@ * This will contact the TestAPI to delete an existing test case. */ function deleteTestCase(name) { - ctrl.showError = false; - ctrl.showSuccess = false; ctrl.testCasesRequest = $http.delete(ctrl.requestUrl+"/"+name).success(function (data) { loadDetails(); - ctrl.showSuccess = true ; - ctrl.successMessage = "Test case is successfully deleted" + ctrl.success = "Test case is successfully deleted"; + ctrl.toastSuccess(); }).catch(function (error) { - ctrl.showError = true; - ctrl.error = data.statusText; + ctrl.error = error.statusText; + ctrl.toastError(); }); } @@ -218,8 +226,8 @@ ctrl.data = data; }).catch(function (error) { ctrl.data = null; - ctrl.showError = true; ctrl.error = error.statusText; + ctrl.toastError() }); } ctrl.loadDetails(); @@ -271,9 +279,15 @@ * inputs. */ function confirm() { - $uibModalInstance.close(); if (angular.isDefined(ctrl.data.successHandler)) { - ctrl.data.successHandler(ctrl.name, ctrl.testcase); + if(ctrl.testcase.name){ + ctrl.data.successHandler(ctrl.name, ctrl.testcase).success( function(){ + $uibModalInstance.close(); + }) + } + else{ + ctrl.data.successHandler(ctrl.name, ctrl.testcase) + } } } diff --git a/testapi/opnfv_testapi/ui/components/projects/projects.html b/testapi/opnfv_testapi/ui/components/projects/projects.html index 5d514d1..3098aa2 100644 --- a/testapi/opnfv_testapi/ui/components/projects/projects.html +++ b/testapi/opnfv_testapi/ui/components/projects/projects.html @@ -21,16 +21,12 @@ <input type="text" class="form-control search" ng-enter="ctrl.listProjects()" ng-Model="ctrl.filterText" style="width:80%;" placeholder="Search By Name"> </div> </div> -<div class='clo-md-12'> - <div ng-show="ctrl.showError" class="alert alert-danger" role="alert"> - <span class="pull-right"> {{ctrl.error}}</span> - <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> - </div> - <div ng-show="ctrl.showSuccess" class="alert alert-success" role="alert"> - <span class="pull-right"> {{ctrl.success}}</span> - <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span> - </div> -</div> +<div ng-class="{'show': ctrl.showError}" id="toast" class="error"> + <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true" ></span> + {{ctrl.error}}</div> +<div ng-class="{'show': ctrl.showSuccess}" id="toast" class="success"> + <span class="glyphicon glyphicon-ok" aria-hidden="true"></span> + {{ctrl.success}}</div> <div class='clo-md-12' style="padding-right:0px"> <div class="table-responsive"> <table class="table table-bordered table-hover" ng-data="ctrl.data.projects"> diff --git a/testapi/opnfv_testapi/ui/components/projects/projectsController.js b/testapi/opnfv_testapi/ui/components/projects/projectsController.js index 4f0af0f..42100bd 100644 --- a/testapi/opnfv_testapi/ui/components/projects/projectsController.js +++ b/testapi/opnfv_testapi/ui/components/projects/projectsController.js @@ -21,7 +21,7 @@ ProjectsController.$inject = [ '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl', - 'raiseAlert', 'confirmModal', 'authenticate', 'keepState', 'sortService' + 'raiseAlert', 'confirmModal', 'authenticate', 'keepState', 'sortService', '$timeout' ]; /** @@ -30,7 +30,7 @@ * through projects declared in TestAPI. */ function ProjectsController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl, - raiseAlert, confirmModal, authenticate, keepState, sortService) { + raiseAlert, confirmModal, authenticate, keepState, sortService, $timeout) { var ctrl = this; ctrl.url = testapiApiUrl + '/projects'; @@ -51,27 +51,41 @@ ctrl.name = ''; ctrl.details = ''; ctrl.ascending = false; + ctrl.toastError = toastError + ctrl.toastSuccess = toastSuccess + + function toastError() { + ctrl.showError = true + $timeout(function(){ ctrl.showError = false;}, 7000); + } + + function toastSuccess() { + ctrl.showSuccess = true + $timeout(function(){ ctrl.showSuccess = false;}, 7000); + } /** * This will contact the TestAPI to create a new project. */ function create(project) { - ctrl.showError = false; - ctrl.showSuccess = false; var projects_url = ctrl.url; var body = { name: project.name, description: project.description }; - ctrl.projectsRequest = - $http.post(projects_url, body).success(function (data){ - ctrl.showSuccess = true ; - ctrl.success = "Project is successfully created." + ctrl.projectsRequest = $http.post(projects_url, body) + ctrl.projectsRequest.success(function (data){ + ctrl.success = "Project is successfully created."; ctrl.listProjects(); + ctrl.toastSuccess(); + ctrl.request = true; }).catch(function (data) { - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError(); + ctrl.request = false; }); + + return ctrl.projectsRequest } function sortByName(){ @@ -135,16 +149,17 @@ ctrl.showError = false; ctrl.showSuccess = false; var projectUrl = ctrl.url + '/' + name; - ctrl.testCasesRequest = - $http.put(projectUrl, project).success(function (data){ - ctrl.showSuccess = true ; + ctrl.projectRequest = $http.put(projectUrl, project) + ctrl.projectRequest.success(function (data){ ctrl.success = "Project is successfully updated." - listProjects(); + ctrl.listProjects(); + ctrl.toastSuccess(); }) .catch(function (data) { - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError(); }); + return ctrl.projectRequest } /** @@ -174,8 +189,8 @@ } }).catch(function (data) { ctrl.data = null; - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError(); }); } @@ -190,13 +205,12 @@ function projectDelete(projectName){ var projectUrl = ctrl.url + "/" + projectName $http.delete(projectUrl).success(function(){ - ctrl.showSuccess = true ; ctrl.success = "Projects is successfully deleted" + ctrl.toastSuccess(); ctrl.listProjects(); }).catch(function (data) { - ctrl.showError = true; - ctrl.showSuccess = false; ctrl.error = data.statusText; + ctrl.toastError(); }); } @@ -277,11 +291,15 @@ function confirm() { if (angular.isDefined(ctrl.data.successHandler)) { if(ctrl.project.name != ""){ - $uibModalInstance.close(); + var success = false; if(ctrl.data.project){ - ctrl.data.successHandler(ctrl.projectName, ctrl.project); + ctrl.data.successHandler(ctrl.projectName, ctrl.project).success(function (data){ + $uibModalInstance.close(); + }) }else{ - ctrl.data.successHandler(ctrl.project); + ctrl.data.successHandler(ctrl.project).success(function (data){ + $uibModalInstance.close(); + }) } }else{ ctrl.showCreateError = true; diff --git a/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenario.html b/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenario.html index 4f0a580..d6d4257 100644 --- a/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenario.html +++ b/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenario.html @@ -225,14 +225,10 @@ </div> </div> <div class="row" style="margin-bottom:24px;"></div> -<div class='clo-md-12'> - <div ng-show="ctrl.showError" class="alert alert-danger" role="alert"> - <span class="pull-right"> {{ctrl.error}}</span> - <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> - </div> - <div ng-show="ctrl.showSuccess" class="alert alert-success" role="alert"> - <span class="pull-right"> {{ctrl.success}}</span> - <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span> - </div> -</div> +<div ng-class="{'show': ctrl.showError}" id="toast" class="error"> + <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true" ></span> + {{ctrl.error}}</div> +<div ng-class="{'show': ctrl.showSuccess}" id="toast" class="success"> + <span class="glyphicon glyphicon-ok" aria-hidden="true"></span> + {{ctrl.success}}</div> <div class="row" style="margin-bottom:24px;"></div>
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js b/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js index a0cd5eb..e17718f 100644 --- a/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js +++ b/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js @@ -21,7 +21,7 @@ ScenarioController.$inject = [ '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert', - 'confirmModal', 'authenticate' + 'confirmModal', 'authenticate', '$timeout' ]; /** @@ -30,7 +30,7 @@ * through Scenario declared in TestAPI. */ function ScenarioController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl, - raiseAlert, confirmModal, authenticate) { + raiseAlert, confirmModal, authenticate, $timeout) { var ctrl = this; ctrl.name = $state.params['name']; ctrl.url = testapiApiUrl + '/scenarios?name=' + ctrl.name; @@ -73,7 +73,18 @@ ctrl.buttonInstaller = true ctrl.buttonVersion = true ctrl.buttonProject = true + ctrl.toastError = toastError + ctrl.toastSuccess = toastSuccess + function toastError() { + ctrl.showError = true + $timeout(function(){ ctrl.showError = false;}, 3000); + } + + function toastSuccess() { + ctrl.showSuccess = true + $timeout(function(){ ctrl.showSuccess = false;}, 3000); + } /** * This will contact the TestAPI to get a listing of declared projects. */ @@ -84,8 +95,8 @@ ctrl.data = data; }).catch(function (error) { ctrl.data = null; - ctrl.showError = true; ctrl.error = error.statusText + ctrl.toastError() }); } @@ -203,13 +214,13 @@ function deleteInstaller(data){ ctrl.installerReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/installers" $http.delete(ctrl.installerReqest, {data: data.installers, headers: {'Content-Type': 'application/json'}}).success(function (data){ - ctrl.showSuccess = true ; ctrl.success = "Installer is successfully deleted." + ctrl.toastSuccess(); ctrl.loadDetails(); }) .catch(function (data) { - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError() }); } @@ -225,16 +236,18 @@ function addInstaller(installer){ var installers = [] installers.push(installer) - ctrl.installerReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/installers" - $http.post(ctrl.installerReqest, installers).success(function (data){ - ctrl.showSuccess = true ; + ctrl.installerRequestUrl = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/installers" + ctrl.installerRequest = $http.post(ctrl.installerRequestUrl, installers) + ctrl.installerRequest.success(function (data){ ctrl.success = "Installers are successfully updated." ctrl.loadDetails(); + ctrl.toastSuccess(); }) .catch(function (data) { - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError(); }); + return ctrl.installerRequest } function openAddInstaller(){ @@ -254,16 +267,18 @@ } function addVersion(versions, installer){ - ctrl.versionReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/versions?installer="+installer - $http.post(ctrl.versionReqest, versions).success(function (data){ - ctrl.showSuccess = true ; + ctrl.versionRequestUrl = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/versions?installer="+installer + ctrl.versionRequest = $http.post(ctrl.versionRequestUrl, versions) + ctrl.versionRequest.success(function (data){ ctrl.success = "Versions are successfully updated." ctrl.loadDetails(); + ctrl.toastSuccess() }) .catch(function (data) { - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError() }); + return ctrl.versionRequest; } function openDeleteVersionModal(version, installer){ @@ -279,13 +294,13 @@ function deleteVersion(data){ ctrl.versionReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/versions?installer="+data.installer $http.delete(ctrl.versionReqest, {data: data.version, headers: {'Content-Type': 'application/json'}}).success(function (data){ - ctrl.showSuccess = true ; ctrl.success = "Versions are successfully deleted." ctrl.loadDetails(); + ctrl.toastSuccess(); }) .catch(function (data) { - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError(); }); } @@ -307,16 +322,18 @@ } function addProject(project, version, installer){ - ctrl.projectReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/projects?installer="+installer+"&version="+version - $http.post(ctrl.projectReqest, project).success(function (data){ - ctrl.showSuccess = true ; + ctrl.projectRequestUrl = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/projects?installer="+installer+"&version="+version + ctrl.projectRequest= $http.post(ctrl.projectRequestUrl, project) + ctrl.projectRequest.success(function (data){ ctrl.success = "Projects are successfully updated." ctrl.loadDetails(); + ctrl.toastSuccess(); }) .catch(function (data) { - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError(); }); + return ctrl.projectRequest; } function openAddProjectModal(version, installer){ @@ -338,16 +355,18 @@ } function addCustom(custom,project,version,installer){ - ctrl.customReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/customs?installer="+installer+"&version="+version+"&project="+ project - $http.post(ctrl.customReqest, custom).success(function (data){ - ctrl.showSuccess = true ; + ctrl.customRequestUrl = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/customs?installer="+installer+"&version="+version+"&project="+ project + ctrl.customRequest = $http.post(ctrl.customRequestUrl, custom) + ctrl.customRequest.success(function (data){ ctrl.success = "Customs are successfully updated." ctrl.loadDetails(); + ctrl.toastSuccess(); }) .catch(function (data) { - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError(); }); + return ctrl.customRequest } function openDeleteCustomModal(custom,project,version,installer){ @@ -365,13 +384,13 @@ function deleteCustom(data){ ctrl.customReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/customs?installer="+data.installer+"&version="+data.version+"&project="+ data.project $http.delete(ctrl.customReqest, {data: data.customs, headers: {'Content-Type': 'application/json'}}).success(function (data){ - ctrl.showSuccess = true ; ctrl.success = "Customs are successfully deleted." ctrl.loadDetails(); + ctrl.toastSuccess(); }) .catch(function (data) { - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError(); }); } @@ -408,13 +427,13 @@ function deleteProject(data){ ctrl.projectReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/projects?installer="+data.installer+"&version="+data.version $http.delete(ctrl.projectReqest, {data: data.projects, headers: {'Content-Type': 'application/json'}}).success(function (data){ - ctrl.showSuccess = true ; - ctrl.success = "Projects are successfully Deleted." + ctrl.success = "Projects are successfully Deleted."; + ctrl.toastSuccess(); ctrl.loadDetails(); }) .catch(function (data) { - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError(); }); } @@ -443,8 +462,11 @@ ctrl.customs = custom.split(/[ ,]+/).filter(Boolean); } console.log(ctrl.customs) - ctrl.data.successHandler(ctrl.customs,ctrl.data.project,ctrl.data.version,ctrl.data.installer); - $uibModalInstance.dismiss('cancel'); + ctrl.data.successHandler( + ctrl.customs, ctrl.data.project, + ctrl.data.version,ctrl.data.installer).success(function(){ + $uibModalInstance.dismiss('cancel'); + }); } @@ -486,8 +508,10 @@ */ function confirm() { ctrl.projects.push(ctrl.project) - ctrl.data.successHandler(ctrl.projects, ctrl.data.version, ctrl.data.installer); - $uibModalInstance.dismiss('cancel'); + ctrl.data.successHandler( + ctrl.projects, ctrl.data.version, ctrl.data.installer).success( function(){ + $uibModalInstance.dismiss('cancel'); + }); } @@ -545,8 +569,9 @@ */ function confirm() { ctrl.versions.push(ctrl.version) - ctrl.data.successHandler(ctrl.versions, ctrl.data.installer); - $uibModalInstance.dismiss('cancel'); + ctrl.data.successHandler(ctrl.versions, ctrl.data.installer).success(function(){ + $uibModalInstance.dismiss('cancel'); + }); } diff --git a/testapi/opnfv_testapi/ui/components/scenarios/scenarios.html b/testapi/opnfv_testapi/ui/components/scenarios/scenarios.html index bde946c..8d23449 100644 --- a/testapi/opnfv_testapi/ui/components/scenarios/scenarios.html +++ b/testapi/opnfv_testapi/ui/components/scenarios/scenarios.html @@ -10,16 +10,12 @@ <i class="fa fa-plus"></i>Create</button> </div> </div> -<div class='clo-md-12'> - <div ng-show="ctrl.showError" class="alert alert-danger" role="alert"> - <span class="pull-right"> {{ctrl.error}}</span> - <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> - </div> - <div ng-show="ctrl.showCreateSuccess" class="alert alert-success" role="alert"> - <span class="pull-right"> {{ctrl.success}}</span> - <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span> - </div> -</div> +<div ng-class="{'show': ctrl.showError}" id="toast" class="error"> + <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true" ></span> + {{ctrl.error}}</div> +<div ng-class="{'show': ctrl.showSuccess}" id="toast" class="success"> + <span class="glyphicon glyphicon-ok" aria-hidden="true"></span> + {{ctrl.success}}</div> <div class='clo-md-12' style="padding-right:0px"> <div class="table-responsive"> <table class="table table-bordered table-hover" ng-data="ctrl.data.scenarios"> diff --git a/testapi/opnfv_testapi/ui/components/scenarios/scenariosController.js b/testapi/opnfv_testapi/ui/components/scenarios/scenariosController.js index 240287c..0aa5bf0 100644 --- a/testapi/opnfv_testapi/ui/components/scenarios/scenariosController.js +++ b/testapi/opnfv_testapi/ui/components/scenarios/scenariosController.js @@ -21,7 +21,7 @@ ScenariosController.$inject = [ '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl', - 'raiseAlert', 'confirmModal', 'sortService' + 'raiseAlert', 'confirmModal', 'sortService', '$timeout' ]; /** @@ -30,7 +30,7 @@ * through projects declared in TestAPI. */ function ScenariosController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl, - raiseAlert, confirmModal, sortService) { + raiseAlert, confirmModal, sortService, $timeout) { var ctrl = this; ctrl.url = testapiApiUrl + '/scenarios'; @@ -47,6 +47,18 @@ ctrl.sortBy = sortBy ctrl.checkBox = []; ctrl.sortName = false + ctrl.toastError = toastError + ctrl.toastSuccess = toastSuccess + + function toastError() { + ctrl.showError = true + $timeout(function(){ ctrl.showError = false;}, 3000); + } + + function toastSuccess() { + ctrl.showSuccess = true + $timeout(function(){ ctrl.showSuccess = false;}, 3000); + } function openUpdateModal(name){ $uibModal.open({ @@ -78,12 +90,12 @@ var scenarioURL = ctrl.url+"/"+name; ctrl.scenarioRequest = $http.delete(scenarioURL).success(function (data){ - ctrl.showCreateSuccess = true; ctrl.success = "Scenario is successfully deleted."; ctrl.listScenarios(); + ctrl.toastSuccess(); }).catch(function (data) { - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError() }); } @@ -117,15 +129,21 @@ var body = { "name": newName } - ctrl.scenarioRequest = - $http.put(scenarioURL, body).success(function (data){ - ctrl.showCreateSuccess = true; + if(newName){ + ctrl.scenarioRequest = $http.put(scenarioURL, body) + ctrl.scenarioRequest.success(function (data){ ctrl.success = "Scenario is successfully Updated." - ctrl.listScenarios() + ctrl.listScenarios(); + ctrl.toastSuccess(); }).catch(function (data) { - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError(); }); + return ctrl.scenarioRequest + }else{ + ctrl.error = "Name is missing"; + ctrl.toastError(); + } } function viewScenario(name){ @@ -133,14 +151,17 @@ } function createScenario(scenario) { - ctrl.scenarioRequest = - $http.post(ctrl.url, scenario).success(function (data){ - ctrl.showCreateSuccess = true; - ctrl.success = "Scenario is successfully created." + ctrl.scenarioRequest = $http.post(ctrl.url, scenario) + + ctrl.scenarioRequest.success(function (data){ + ctrl.success = "Scenario is successfully created."; + ctrl.toastSuccess(); }).catch(function (data) { - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError(); }); + + return ctrl.scenarioRequest; } function listScenarios() { @@ -151,8 +172,8 @@ ctrl.sortBy() }).catch(function (data) { ctrl.data = null; - ctrl.showError = true; ctrl.error = data.statusText; + ctrl.toastError(); }); } @@ -183,8 +204,8 @@ * edit the project's details */ angular.module('testapiApp').controller('scenarioModalController', scenarioModalController); - scenarioModalController.$inject = ['$scope', '$uibModal', '$uibModalInstance', 'data']; - function scenarioModalController($scope, $uibModal, $uibModalInstance, data) { + scenarioModalController.$inject = ['$scope', '$uibModal', '$uibModalInstance', 'data', '$q']; + function scenarioModalController($scope, $uibModal, $uibModalInstance, data, $q) { var ctrl = this; ctrl.confirm = confirm; ctrl.cancel = cancel; @@ -201,8 +222,9 @@ * inputs. */ function confirm() { - ctrl.data.successHandler(ctrl.scenario); - $uibModalInstance.dismiss('cancel'); + ctrl.data.successHandler(ctrl.scenario).success(function(){ + $uibModalInstance.dismiss('cancel'); + }); } @@ -215,6 +237,9 @@ function handleModalData(installer){ ctrl.scenario.installers.push(installer) + var deferred = $q.defer(); + deferred.resolve(); + return deferred.promise; } function openInstallerModal(){ @@ -259,8 +284,9 @@ * inputs. */ function confirm() { - ctrl.data.successHandler(ctrl.installer); - $uibModalInstance.dismiss('cancel'); + ctrl.data.successHandler(ctrl.installer).success(function(){ + $uibModalInstance.dismiss('cancel'); + }); } @@ -472,9 +498,9 @@ * inputs. */ function confirm() { - ctrl.data.successHandler(ctrl.name,ctrl.data.name); - $uibModalInstance.dismiss('cancel'); - + ctrl.data.successHandler(ctrl.name,ctrl.data.name).success( function() { + $uibModalInstance.dismiss('cancel'); + }) } /** diff --git a/testapi/opnfv_testapi/ui/package.json b/testapi/opnfv_testapi/ui/package.json index dc99239..2d4eb6e 100644 --- a/testapi/opnfv_testapi/ui/package.json +++ b/testapi/opnfv_testapi/ui/package.json @@ -3,6 +3,7 @@ "grunt": "~1.0.1", "grunt-contrib-connect": "^1.0.2", "grunt-contrib-copy": "^1.0.0", + "grunt-convert": "^0.1.12", "grunt-karma": "~2.0.0", "grunt-protractor-coverage": "^0.2.18", "grunt-protractor-runner": "~5.0.0", diff --git a/testapi/requirements.txt b/testapi/requirements.txt index f752a64..7f50fd7 100644 --- a/testapi/requirements.txt +++ b/testapi/requirements.txt @@ -9,4 +9,5 @@ epydoc>=0.3.1 six>=1.9.0 # MIT motor # Apache-2.0 python-cas -requests[security]
\ No newline at end of file +requests[security] +futures
\ No newline at end of file diff --git a/testapi/testapi-client/etc/client.creds b/testapi/testapi-client/etc/client.creds index a082047..ee2a0ab 100644 --- a/testapi/testapi-client/etc/client.creds +++ b/testapi/testapi-client/etc/client.creds @@ -1,3 +1,4 @@ export testapi_url=http://localhost:8000/api/v1 export testapi_cas_signin_return=/auth/signin_return -export testapi_cas_auth_url=https://identity.linuxfoundation.org/user/login?destination=cas/login%3Fservice%3D
\ No newline at end of file +export testapi_cas_auth_url=https://identity.linuxfoundation.org/user/login?destination=cas/login%3Fservice%3D +export testapi_token=changeme
\ No newline at end of file diff --git a/testapi/testapi-client/setup.cfg b/testapi/testapi-client/setup.cfg index b89fba4..ee1ba54 100644 --- a/testapi/testapi-client/setup.cfg +++ b/testapi/testapi-client/setup.cfg @@ -64,6 +64,10 @@ testapi = deployresult get = testapiclient.cli.deployresults:DeployresultGet deployresult getone = testapiclient.cli.deployresults:DeployresultGetOne + result create = testapiclient.cli.results:ResultCreate + result get = testapiclient.cli.results:ResultGet + result getone = testapiclient.cli.results:ResultGetOne + [egg_info] tag_build = tag_date = 0 diff --git a/testapi/testapi-client/testapiclient/cli/deployresults.py b/testapi/testapi-client/testapiclient/cli/deployresults.py index a6fe13e..1ca0bef 100644 --- a/testapi/testapi-client/testapiclient/cli/deployresults.py +++ b/testapi/testapi-client/testapiclient/cli/deployresults.py @@ -2,6 +2,7 @@ import json from testapiclient.utils import command from testapiclient.utils import urlparse +from testapiclient.models import deployresult def deployresults_url(): @@ -85,13 +86,10 @@ class DeployresultCreate(command.ShowOne): parser.add_argument('deployresult', type=json.loads, help='Deployresult create request format:\n' - '\'{"job_name" : "","scenario" : "",' - '"stop_date" : "", "build_id" : "",' - '"upstream_job_name": "",' - '"version" : "", "pod_name" : "",' - '"criteria" : "", "installer" : "",' - '"upstream_build_id" : "",' - '"start_date" : "", "details" : ""}\'') + '\'{}\''.format(json.dumps( + deployresult.DeployResultCreateRequest( + ).__dict__ + ))) return parser def take_action(self, parsed_args): diff --git a/testapi/testapi-client/testapiclient/cli/pods.py b/testapi/testapi-client/testapiclient/cli/pods.py index 8d0970b..a7706f6 100644 --- a/testapi/testapi-client/testapiclient/cli/pods.py +++ b/testapi/testapi-client/testapiclient/cli/pods.py @@ -1,7 +1,9 @@ import json +from testapiclient.client import pods from testapiclient.utils import command from testapiclient.utils import urlparse +from testapiclient.models import pods as pm def pods_url(): @@ -60,15 +62,17 @@ class PodCreate(command.ShowOne): parser.add_argument('pod', type=json.loads, help='Pod create request format :\n' - '\'{"role": "", "name": "", "details": "", ' - '"mode": ""}\',\n role should be either ' + '\'{}\''.format(json.dumps( + pm.PodCreateRequest().__dict__ + )) + + '\n role should be either ' '"community-ci" or "production-ci", and ' 'mode should be either "metal" or "virtual.') return parser def take_action(self, parsed_args): - return self.format_output( - self.app.client_manager.post(pods_url(), parsed_args.pod)) + client = pods.PodsClient(client_manager=self.app.client_manager) + return self.format_output(client.create(parsed_args.pod)) class PodDelete(command.Command): diff --git a/testapi/testapi-client/testapiclient/cli/projects.py b/testapi/testapi-client/testapiclient/cli/projects.py index 510acc8..2fa5b5b 100644 --- a/testapi/testapi-client/testapiclient/cli/projects.py +++ b/testapi/testapi-client/testapiclient/cli/projects.py @@ -2,6 +2,7 @@ import json from testapiclient.utils import command from testapiclient.utils import urlparse +from testapiclient.models import project def projects_url(): @@ -51,9 +52,10 @@ class ProjectCreate(command.ShowOne): parser = super(ProjectCreate, self).get_parser(prog_name) parser.add_argument('project', type=json.loads, - help='Project create request format :{' - ' "name": (required)"", ' - '"description": (optional)""}') + help='Project create request format :\n' + '\'{}\''.format(json.dumps( + project.ProjectCreateRequest().__dict__ + ))) return parser def take_action(self, parsed_args): @@ -83,9 +85,10 @@ class ProjectPut(command.ShowOne): help='Update project by name') parser.add_argument('project', type=json.loads, - help='Project Update request format :{' - '"name": (required)"", ' - '"description": (optional)""}') + help='Project Update request format :\n' + '\'{}\''.format(json.dumps( + project.ProjectCreateRequest().__dict__ + ))) return parser def take_action(self, parsed_args): diff --git a/testapi/testapi-client/testapiclient/cli/results.py b/testapi/testapi-client/testapiclient/cli/results.py new file mode 100644 index 0000000..5500501 --- /dev/null +++ b/testapi/testapi-client/testapiclient/cli/results.py @@ -0,0 +1,97 @@ +import json + +from testapiclient.utils import command +from testapiclient.utils import urlparse +from testapiclient.models import result + + +def results_url(): + return urlparse.resource_join('results') + + +def result_url(parsed_args): + return urlparse.path_join(results_url(), parsed_args.result_id) + + +class ResultGet(command.Lister): + + def get_parser(self, prog_name): + parser = super(ResultGet, self).get_parser(prog_name) + parser.add_argument('-case', + help='Search results using tesetcase') + parser.add_argument('-build-tag', + help='Search results using build tag') + parser.add_argument('-from', + help='Search results using from date') + parser.add_argument('-last', + help='Search results using last date') + parser.add_argument('-scenario', + help='Search results using scenario') + parser.add_argument('-period', + help='Search results using period') + parser.add_argument('-project', + help='Search results using project') + parser.add_argument('-to', + help='Search results using to') + parser.add_argument('---version', + help='Search results using version') + parser.add_argument('-criteria', + help='Search results using version') + parser.add_argument('-installer', + help='Search results using installer') + parser.add_argument('-pod', + help='Search results using pod') + parser.add_argument('-page', + help='Search results using page') + return parser + + def take_action(self, parsed_args): + columns = ( + '_id', + 'pod_name', + 'project_name', + 'case_name', + 'installer', + 'version', + 'scenario', + 'criteria', + 'start_date' + ) + data = self.app.client_manager.get( + urlparse.query_by(results_url(), + ['case', 'build_tag', 'from', 'last', + 'scenario', 'period', 'project', + 'to', 'version', + 'criteria', 'installer', 'pod', 'page'], + parsed_args)) + return self.format_output(columns, data.get('results', [])) + + +class ResultGetOne(command.ShowOne): + + def get_parser(self, prog_name): + parser = super(ResultGetOne, self).get_parser(prog_name) + parser.add_argument('result_id', + help='Search result by result id') + return parser + + def take_action(self, parsed_args): + return self.format_output( + self.app.client_manager.get(result_url(parsed_args))) + + +class ResultCreate(command.ShowOne): + + def get_parser(self, prog_name): + parser = super(ResultCreate, self).get_parser(prog_name) + parser.add_argument('result', + type=json.loads, + help='Result create request format:\n' + '\'{}\''.format(json.dumps( + result.ResultCreateRequest().__dict__))) + return parser + + def take_action(self, parsed_args): + return self.format_output( + self.app.client_manager.post( + results_url(), parsed_args.result)) diff --git a/testapi/testapi-client/testapiclient/cli/scenarios.py b/testapi/testapi-client/testapiclient/cli/scenarios.py index 507705a..197ee0c 100644 --- a/testapi/testapi-client/testapiclient/cli/scenarios.py +++ b/testapi/testapi-client/testapiclient/cli/scenarios.py @@ -2,6 +2,7 @@ import json from testapiclient.utils import command from testapiclient.utils import urlparse +from testapiclient.models import scenario def scenarios_url(): @@ -64,22 +65,37 @@ class ScenarioCreate(command.ShowOne): parser.add_argument('scenario', type=json.loads, help='Scenario create request format :\n' - '\'{ "installers": [], "name": ""}\',\n' - 'Intaller create request format :\n' - '\'{"installer": "","versions": []}\',\n' - 'Version create request format :\n' - '\'{"owner": "","version": "",' - '"projects": []}\',\n' - 'Project create request format :\n' - '\'{"project": "","customs": [],' - '"scores": [],' - '"trust_indicators": []}\',\n' - 'Custom create request format :\n' + '\'{}\''.format(json.dumps( + scenario.ScenarioCreateRequest( + ).__dict__ + )) + + '\n Intaller create request format :\n' + '\'{}\''.format(json.dumps( + scenario.ScenarioInstallerCreateRequest( + ).__dict__ + )) + + '\n Version create request format :\n' + '\'{}\''.format(json.dumps( + scenario.ScenarioVersionCreateRequest( + ).__dict__ + )) + + '\n Project create request format :\n' + '\'{}\''.format(json.dumps( + scenario.ScenarioProjectCreateRequest( + ).__dict__ + )) + + '\n Custom create request format :\n' '\'["asf","saf"]\',\n' - 'Score create request format :\n' - '\'{"date": "", "score": ""}\',\n' - 'Trust Indicators create request format :\n' - '\'{"date": "", "status": ""}\'') + '\n Score create request format :\n' + '\'{}\''.format(json.dumps( + scenario.ScenarioScoreCreateRequest( + ).__dict__ + )) + + '\nTrustIndicator create request format:\n' + '\'{}\''.format(json.dumps( + scenario.ScenarioTICreateRequest( + ).__dict__ + ))) return parser def take_action(self, parsed_args): @@ -110,23 +126,38 @@ class ScenarioPut(command.ShowOne): help='Update scenario by name') parser.add_argument('scenario', type=json.loads, - help='Scenario create request format :\n' - '\'{ "installers": [], "name": ""}\',\n' - 'Intaller create request format :\n' - '\'{"installer": "","versions": []}\',\n' - 'Version create request format :\n' - '\'{"owner": "","version": "",' - '"projects": []}\',\n' - 'Project create request format :\n' - '\'{"project": "","customs": [],' - '"scores": [],' - '"trust_indicators": []}\',\n' - 'Custom create request format :\n' + help='Scenario create request format :\n' + + '\'{}\''.format(json.dumps( + scenario.ScenarioCreateRequest( + ).__dict__ + )) + + '\n Intaller create request format :\n' + '\'{}\''.format(json.dumps( + scenario.ScenarioInstallerCreateRequest( + ).__dict__ + )) + + '\n Version create request format :\n' + '\'{}\''.format(json.dumps( + scenario.ScenarioVersionCreateRequest( + ).__dict__ + )) + + '\n Project create request format :\n' + '\'{}\''.format(json.dumps( + scenario.ScenarioProjectCreateRequest( + ).__dict__ + )) + + '\n Custom create request format :\n' '\'["asf","saf"]\',\n' - 'Score create request format :\n' - '\'{"date": "", "score": ""}\',\n' - 'Trust Indicators create request format :\n' - '\'{"date": "", "status": ""}\'') + '\n Score create request format :\n' + '\'{}\''.format(json.dumps( + scenario.ScenarioScoreCreateRequest( + ).__dict__ + )) + + '\nTrustIndicator create request format:\n' + '\'{}\''.format(json.dumps( + scenario.ScenarioTICreateRequest( + ).__dict__ + ))) return parser def take_action(self, parsed_args): @@ -145,7 +176,10 @@ class InstallerCreate(command.Command): parser.add_argument('installer', type=json.loads, help='Intaller create request format :\n' - '\'[{"installer": "","versions": []}]\',\n') + '\'{}\''.format(json.dumps( + scenario.ScenarioInstallerCreateRequest( + ).__dict__ + ))) return parser def take_action(self, parsed_args): @@ -186,7 +220,10 @@ class InstallerPut(command.Command): parser.add_argument('installer', type=json.loads, help='Intaller create request format :\n' - '\'[{"installer": "","versions": []}]\',\n') + '\'{}\''.format(json.dumps( + scenario.ScenarioInstallerCreateRequest( + ).__dict__ + ))) return parser def take_action(self, parsed_args): @@ -209,10 +246,10 @@ class VersionCreate(command.Command): parser.add_argument('version', type=json.loads, help='version create request format :\n' - '\'[{"owner":(string),' - '"version": (string),' - '"projects": (array[ScenarioProject])' - '}]\',\n') + '\'{}\''.format(json.dumps( + scenario.ScenarioVersionCreateRequest( + ).__dict__ + ))) return parser def take_action(self, parsed_args): @@ -261,10 +298,10 @@ class VersionPut(command.Command): parser.add_argument('version', type=json.loads, help='version update request format :\n' - '\'[{"owner":(string),' - '"version": (string),' - '"projects": (array[ScenarioProject])' - '}]\',\n') + '\'{}\''.format(json.dumps( + scenario.ScenarioVersionCreateRequest( + ).__dict__ + ))) return parser def take_action(self, parsed_args): @@ -320,10 +357,10 @@ class ProjectCreate(command.Command): parser.add_argument('project', type=json.loads, help='Project create request format :\n' - '\'[{ "project" (string),' - '"scores": (array[ScenarioScore]),' - '"trust_indicators": (array[ScenarioTI]),' - '"customs": (array[string]) }]\',\n') + '\'{}\''.format(json.dumps( + scenario.ScenarioProjectCreateRequest( + ).__dict__ + ))) return parser def take_action(self, parsed_args): @@ -378,10 +415,10 @@ class ProjectPut(command.Command): parser.add_argument('project', type=json.loads, help='Project update request format :\n' - '\'[{ "project" (string),' - '"scores": (array[ScenarioScore]),' - '"trust_indicators": (array[ScenarioTI]),' - '"customs": (array[string]) }]\',\n') + '\'{}\''.format(json.dumps( + scenario.ScenarioProjectCreateRequest( + ).__dict__ + ))) return parser def take_action(self, parsed_args): @@ -511,8 +548,10 @@ class TrustIndicatorCreate(command.Command): parser.add_argument('trust_indicator', type=json.loads, help='trust indicator create request format :\n' - '\'{ "date": (string, optional),' - '"status": (string, optional) }\',\n') + '\'{}\''.format(json.dumps( + scenario.ScenarioTICreateRequest( + ).__dict__ + ))) return parser def take_action(self, parsed_args): @@ -547,8 +586,10 @@ class ScoreCreate(command.Command): parser.add_argument('score', type=json.loads, help='score create request format :\n' - '\'{ "date": (string, optional),' - '"score" : (string, optional) }\',\n') + '\'{}\''.format(json.dumps( + scenario.ScenarioScoreCreateRequest( + ).__dict__ + ))) return parser def take_action(self, parsed_args): diff --git a/testapi/testapi-client/testapiclient/cli/testcases.py b/testapi/testapi-client/testapiclient/cli/testcases.py index 6c97edb..3052c18 100644 --- a/testapi/testapi-client/testapiclient/cli/testcases.py +++ b/testapi/testapi-client/testapiclient/cli/testcases.py @@ -2,6 +2,7 @@ import json from testapiclient.utils import command from testapiclient.utils import urlparse +from testapiclient.models import testcase def testcases_url(name): @@ -60,12 +61,9 @@ class TestcaseCreate(command.ShowOne): parser.add_argument('testcase', type=json.loads, help='Testcase create request format:\n' - '\'{"run": "", "name": "", "ci_loop": "",' - '"tags": "",\n "url": "", "blocking": "",' - '"domains": "", "dependencies": "",\n ' - '"version": "", "criteria": "", "tier": "",' - '"trust": "",\n "catalog_description": "",' - '"description": ""}\'') + '\'{}\''.format(json.dumps( + testcase.TestCaseCreateRequest().__dict__ + ))) return parser def take_action(self, parsed_args): @@ -105,12 +103,9 @@ class TestcasePut(command.ShowOne): parser.add_argument('testcase', type=json.loads, help='Testcase Update request format:\n' - '\'{"run": "", "name": "", "ci_loop": "",' - '"tags": "",\n "url": "", "blocking": "",' - '"domains": "", "dependencies": "",\n ' - '"version": "", "criteria": "", "tier": "",' - '"trust": "",\n "catalog_description": "",' - '"description": ""}\'') + '\'{}\''.format(json.dumps( + testcase.TestCaseCreateRequest().__dict__ + ))) return parser def take_action(self, parsed_args): diff --git a/testapi/testapi-client/testapiclient/client/__init__.py b/testapi/testapi-client/testapiclient/client/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/testapi/testapi-client/testapiclient/client/__init__.py diff --git a/testapi/testapi-client/testapiclient/client/base.py b/testapi/testapi-client/testapiclient/client/base.py new file mode 100644 index 0000000..c45c9b7 --- /dev/null +++ b/testapi/testapi-client/testapiclient/client/base.py @@ -0,0 +1,23 @@ +from testapiclient.utils import clientmanager +from testapiclient.utils import urlparse + + +class AuthOption(object): + def __init__(self, user=None, password=None): + self.u = user + self.p = password + + +class Client(object): + + resource = '' + + def __init__(self, user=None, password=None, client_manager=None): + self.url = urlparse.resource_join(self.resource) + if client_manager: + self.clientmanager = client_manager + else: + self.clientmanager = clientmanager.ClientManager( + AuthOption(user, password)) + if self.clientmanager.auth_required: + self.clientmanager.auth() diff --git a/testapi/testapi-client/testapiclient/client/deploy_results.py b/testapi/testapi-client/testapiclient/client/deploy_results.py new file mode 100644 index 0000000..b0724b0 --- /dev/null +++ b/testapi/testapi-client/testapiclient/client/deploy_results.py @@ -0,0 +1,28 @@ +import json + +from testapiclient.client import base +from testapiclient.utils import urlparse + + +class DeployResultsClient(base.Client): + resource = 'deployresults' + + def __init__(self, **kwargs): + super(DeployResultsClient, self).__init__(**kwargs) + + def create(self, testcase_req): + return self.clientmanager.post(self.url, testcase_req) + + def get(self, **queries): + if queries: + return json.dumps( + self.clientmanager.get( + urlparse.query_join(self.url, **queries))['deployresults']) + else: + return json.dumps( + self.clientmanager.get(self.url)['deployresults']) + + def get_one(self, id): + return json.dumps( + self.clientmanager.get( + urlparse.path_join(self.url, id))) diff --git a/testapi/testapi-client/testapiclient/client/pods.py b/testapi/testapi-client/testapiclient/client/pods.py new file mode 100644 index 0000000..d08114f --- /dev/null +++ b/testapi/testapi-client/testapiclient/client/pods.py @@ -0,0 +1,31 @@ +import json + +from testapiclient.client import base +from testapiclient.utils import urlparse + + +class PodsClient(base.Client): + resource = 'pods' + + def __init__(self, **kwargs): + super(PodsClient, self).__init__(**kwargs) + + def create(self, pod_req): + return self.clientmanager.post(self.url, pod_req) + + def get(self, **queries): + if queries: + return json.dumps( + self.clientmanager.get( + urlparse.query_join(self.url, **queries))['pods']) + else: + return json.dumps( + self.clientmanager.get(self.url)['pods']) + + def get_one(self, name): + return json.dumps(self.clientmanager.get( + urlparse.path_join(self.url, name))) + + def delete(self, name): + return self.clientmanager.delete( + urlparse.path_join(self.url, name)) diff --git a/testapi/testapi-client/testapiclient/client/projects.py b/testapi/testapi-client/testapiclient/client/projects.py new file mode 100644 index 0000000..63d00fe --- /dev/null +++ b/testapi/testapi-client/testapiclient/client/projects.py @@ -0,0 +1,35 @@ +import json + +from testapiclient.client import base +from testapiclient.utils import urlparse + + +class ProjectsClient(base.Client): + resource = 'projects' + + def __init__(self, **kwargs): + super(ProjectsClient, self).__init__(**kwargs) + + def create(self, project_req): + return self.clientmanager.post(self.url, project_req) + + def get(self, **queries): + if queries: + return json.dumps( + self.clientmanager.get( + urlparse.query_join(self.url, **queries))['projects']) + else: + return json.dumps( + self.clientmanager.get(self.url)['projects']) + + def get_one(self, name): + return json.dumps(self.clientmanager.get( + urlparse.path_join(self.url, name))) + + def delete(self, name): + return self.clientmanager.delete( + urlparse.path_join(self.url, name)) + + def update(self, name, project_req): + return self.clientmanager.put( + urlparse.path_join(self.url, name), project_req) diff --git a/testapi/testapi-client/testapiclient/client/results.py b/testapi/testapi-client/testapiclient/client/results.py new file mode 100644 index 0000000..7d9ad0e --- /dev/null +++ b/testapi/testapi-client/testapiclient/client/results.py @@ -0,0 +1,28 @@ +import json + +from testapiclient.client import base +from testapiclient.utils import urlparse + + +class ResultsClient(base.Client): + resource = 'results' + + def __init__(self, **kwargs): + super(ResultsClient, self).__init__(**kwargs) + + def create(self, testcase_req): + return self.clientmanager.post(self.url, testcase_req) + + def get(self, **queries): + if queries: + return json.dumps( + self.clientmanager.get( + urlparse.query_join(self.url, **queries))['results']) + else: + return json.dumps( + self.clientmanager.get(self.url)['results']) + + def get_one(self, id): + return json.dumps( + self.clientmanager.get( + urlparse.path_join(self.url, id))) diff --git a/testapi/testapi-client/testapiclient/client/scenarios.py b/testapi/testapi-client/testapiclient/client/scenarios.py new file mode 100644 index 0000000..e5ce2f1 --- /dev/null +++ b/testapi/testapi-client/testapiclient/client/scenarios.py @@ -0,0 +1,177 @@ +import json + +from testapiclient.client import base +from testapiclient.utils import urlparse + + +class ScenariosClient(base.Client): + resource = 'scenarios' + + def __init__(self, **kwargs): + super(ScenariosClient, self).__init__(**kwargs) + + def create(self, scenario_req): + return self.clientmanager.post(self.url, scenario_req) + + def get(self, **queries): + if queries: + return json.dumps( + self.clientmanager.get( + urlparse.query_join(self.url, **queries))['scenarios']) + else: + return json.dumps( + self.clientmanager.get(self.url)['scenarios']) + + def get_one(self, scenario_name): + return json.dumps( + self.clientmanager.get( + urlparse.path_join( + self.url, scenario_name))) + + def delete(self, scenario_name): + return self.clientmanager.delete( + urlparse.path_join( + self.url, scenario_name)) + + def update(self, scenario_name, scenario_req): + return self.clientmanager.put( + urlparse.path_join( + self.url, scenario_name), scenario_req) + + +class InstallersClient(base.Client): + resource = 'scenarios/{}/installers' + + def __init__(self, **kwargs): + super(InstallersClient, self).__init__(**kwargs) + + def delete(self, scenario_name, name): + return self.clientmanager.delete( + self.url.format(scenario_name), [name]) + + def update(self, scenario_name, installer_req): + return self.clientmanager.put( + self.url.format(scenario_name), installer_req) + + def create(self, scenario_name, installer_req): + return self.clientmanager.post( + self.url.format(scenario_name), installer_req) + + +class VersionsClient(base.Client): + resource = 'scenarios/{}/versions' + + def __init__(self, **kwargs): + super(VersionsClient, self).__init__(**kwargs) + + def delete(self, scenario_name, installer, name): + queries = {'installer': installer} + return self.clientmanager.delete( + urlparse.query_join( + self.url.format(scenario_name), **queries), name) + + def update(self, scenario_name, installer, version_req): + queries = {'installer': installer} + return self.clientmanager.put( + urlparse.query_join( + self.url.format(scenario_name), **queries), version_req) + + def create(self, scenario_name, installer, version_req): + queries = {'installer': installer} + return self.clientmanager.post( + urlparse.query_join( + self.url.format(scenario_name), **queries), version_req) + + +class VersionsOwnerClient(base.Client): + resource = 'scenarios/{}/owner' + + def __init__(self, **kwargs): + super(VersionsOwnerClient, self).__init__(**kwargs) + + def update(self, scenario_name, installer, version, owner): + queries = {'installer': installer, 'version': version} + return self.clientmanager.put( + urlparse.query_join( + self.url.format(scenario_name), **queries), owner) + + +class ProjectsClient(base.Client): + resource = 'scenarios/{}/projects' + + def __init__(self, **kwargs): + super(ProjectsClient, self).__init__(**kwargs) + + def delete(self, scenario_name, installer, version, name): + queries = {'installer': installer, 'version': version} + return self.clientmanager.delete( + urlparse.query_join( + self.url.format(scenario_name), **queries), name) + + def update(self, scenario_name, installer, version, project_req): + queries = {'installer': installer, 'version': version} + return self.clientmanager.put( + urlparse.query_join( + self.url.format(scenario_name), **queries), project_req) + + def create(self, scenario_name, installer, version, project_req): + queries = {'installer': installer, 'version': version} + return self.clientmanager.post( + urlparse.query_join( + self.url.format(scenario_name), **queries), project_req) + + +class TrustIndicatorsClient(base.Client): + resource = 'scenarios/{}/trust_indicators' + + def __init__(self, **kwargs): + super(TrustIndicatorsClient, self).__init__(**kwargs) + + def create(self, scenario_name, installer, version, project, trust_in_req): + queries = { + 'installer': installer, 'version': version, 'project': project} + return self.clientmanager.post( + urlparse.query_join( + self.url.format(scenario_name), **queries), trust_in_req) + + +class ScoresClient(base.Client): + resource = 'scenarios/{}/scores' + + def __init__(self, **kwargs): + super(ScoresClient, self).__init__(**kwargs) + + def create(self, scenario_name, installer, version, project, scores_req): + queries = { + 'installer': installer, 'version': version, 'project': project} + return self.clientmanager.post( + urlparse.query_join( + self.url.format(scenario_name), **queries), scores_req) + + +class CustomsClient(base.Client): + resource = 'scenarios/{}/customs' + + def __init__(self, **kwargs): + super(CustomsClient, self).__init__(**kwargs) + + def delete(self, scenario_name, installer, version, project, customs): + queries = { + 'installer': installer, 'version': version, 'project': project} + return self.clientmanager.delete( + urlparse.query_join( + self.url.format(scenario_name), **queries), customs) + + def update(self, scenario_name, installer, version, project, customs): + queries = { + 'installer': installer, 'version': version, 'project': project} + return self.clientmanager.put( + urlparse.query_join( + self.url.format(scenario_name), **queries), customs) + + def create(self, scenario_name, installer, version, project, customs): + queries = { + 'installer': installer, 'version': version, 'project': project} + return self.clientmanager.post( + urlparse.query_join( + self.url.format(scenario_name), **queries), customs) diff --git a/testapi/testapi-client/testapiclient/client/testcases.py b/testapi/testapi-client/testapiclient/client/testcases.py new file mode 100644 index 0000000..bb2b6d3 --- /dev/null +++ b/testapi/testapi-client/testapiclient/client/testcases.py @@ -0,0 +1,36 @@ +import json + +from testapiclient.client import base +from testapiclient.utils import urlparse + + +class TestcasesClient(base.Client): + resource = 'projects/{}/cases' + + def __init__(self, **kwargs): + super(TestcasesClient, self).__init__(**kwargs) + + def create(self, project_name, testcase_req): + return self.clientmanager.post( + self.url.format(project_name), testcase_req) + + def get(self, project_name): + return json.dumps( + self.clientmanager.get( + self.url.format(project_name))['testcases']) + + def get_one(self, project_name, name): + return json.dumps( + self.clientmanager.get( + urlparse.path_join( + self.url.format(project_name), name))) + + def delete(self, project_name, name): + return self.clientmanager.delete( + urlparse.path_join( + self.url.format(project_name), name)) + + def update(self, project_name, name, testcase_req): + return self.clientmanager.put( + urlparse.path_join( + self.url.format(project_name), name), testcase_req) diff --git a/testapi/testapi-client/testapiclient/models/__init__.py b/testapi/testapi-client/testapiclient/models/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/testapi/testapi-client/testapiclient/models/__init__.py diff --git a/testapi/testapi-client/testapiclient/models/deployresult.py b/testapi/testapi-client/testapiclient/models/deployresult.py new file mode 100644 index 0000000..5c13966 --- /dev/null +++ b/testapi/testapi-client/testapiclient/models/deployresult.py @@ -0,0 +1,17 @@ +class DeployResultCreateRequest(): + def __init__( + self, build_id='', scenario='', stop_date='', start_date='', + upstream_job_name='', version='', pod_name='', criteria='', + installer='', upstream_build_id='', job_name='', details=''): + self.build_id = build_id + self.scenario = scenario + self.stop_date = stop_date + self.start_date = start_date + self.upstream_job_name = upstream_job_name + self.version = version + self.pod_name = pod_name + self.criteria = criteria + self.installer = installer + self.upstream_build_id = upstream_build_id + self.job_name = job_name + self.details = details diff --git a/testapi/testapi-client/testapiclient/models/pods.py b/testapi/testapi-client/testapiclient/models/pods.py new file mode 100644 index 0000000..4fa42e7 --- /dev/null +++ b/testapi/testapi-client/testapiclient/models/pods.py @@ -0,0 +1,6 @@ +class PodCreateRequest(object): + def __init__(self, name='', mode='', details='', role=''): + self.name = name + self.mode = mode + self.details = details + self.role = role diff --git a/testapi/testapi-client/testapiclient/models/project.py b/testapi/testapi-client/testapiclient/models/project.py new file mode 100644 index 0000000..fc85588 --- /dev/null +++ b/testapi/testapi-client/testapiclient/models/project.py @@ -0,0 +1,4 @@ +class ProjectCreateRequest(): + def __init__(self, name='', description=''): + self.description = description + self.name = name diff --git a/testapi/testapi-client/testapiclient/models/result.py b/testapi/testapi-client/testapiclient/models/result.py new file mode 100644 index 0000000..766c03a --- /dev/null +++ b/testapi/testapi-client/testapiclient/models/result.py @@ -0,0 +1,16 @@ +class ResultCreateRequest(): + def __init__( + self, project_name='', scenario='', case_name='', pod_name='', + installer='', version='', stop_date='', build_tag='', criteria='', + start_date='', details=''): + self.project_name = project_name + self.scenario = scenario + self.case_name = case_name + self.pod_name = pod_name + self.installer = installer + self.version = version + self.stop_date = stop_date + self.build_tag = build_tag + self.criteria = criteria + self.start_date = start_date + self.details = details diff --git a/testapi/testapi-client/testapiclient/models/scenario.py b/testapi/testapi-client/testapiclient/models/scenario.py new file mode 100644 index 0000000..f4f0f40 --- /dev/null +++ b/testapi/testapi-client/testapiclient/models/scenario.py @@ -0,0 +1,37 @@ +class ScenarioCreateRequest: + def __init__(self, name='', installers=[]): + self.name = name + self.installers = installers + + +class ScenarioInstallerCreateRequest: + def __init__(self, installer='', versions=[]): + self.installer = installer + self.versions = versions + + +class ScenarioVersionCreateRequest: + def __init__(self, version='', owner='', projects=[]): + self.version = version + self.owner = owner + self.projects = projects + + +class ScenarioProjectCreateRequest: + def __init__(self, project='', scores=[], trust_indicators=[], customs=[]): + self.project = project + self.scores = scores + self.trust_indicators = trust_indicators + self.customs = customs + + +class ScenarioScoreCreateRequest: + def __init__(self, score='', date=''): + self.score = score + self.date = date + + +class ScenarioTICreateRequest: + def __init__(self, status='', date=''): + self.status = status + self.date = date diff --git a/testapi/testapi-client/testapiclient/models/testcase.py b/testapi/testapi-client/testapiclient/models/testcase.py new file mode 100644 index 0000000..70d5d78 --- /dev/null +++ b/testapi/testapi-client/testapiclient/models/testcase.py @@ -0,0 +1,20 @@ +class TestCaseCreateRequest(): + def __init__( + self, run='', name='', ci_loop='', tags='', url='', + blocking='', domains='', dependencies='', version='', + criteria='', tier='', trust='', catalog_description='', + description=''): + self.run = run + self.name = name + self.ci_loop = ci_loop + self.tags = tags + self.url = url + self.blocking = blocking + self.domains = domains + self.dependencies = dependencies + self.version = version + self.criteria = criteria + self.tier = tier + self.trust = trust + self.catalog_description = catalog_description + self.description = description diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_app.py b/testapi/testapi-client/testapiclient/tests/unit/test_app.py new file mode 100644 index 0000000..c20b27f --- /dev/null +++ b/testapi/testapi-client/testapiclient/tests/unit/test_app.py @@ -0,0 +1,50 @@ +import urllib + +from mock import mock + +from testapiclient import main +from testapiclient.tests.unit import utils +from testapiclient.tests.unit import fakes + + +class MainTest(utils.TestCommand): + def setUp(self): + super(MainTest, self).setUp() + self.app = main.TestAPIClient() + self.cas_sever = '{}{}{}'.format( + self.env_variables['testapi_cas_auth_url'], + urllib.quote(self.env_variables['testapi_url']), + self.env_variables['testapi_cas_signin_return']) + self.headers = { + 'Content-type': 'application/json', + 'Accept': 'text/plain'} + + def test_auth_success(self): + self.post_mock.return_value = fakes.FakeResponse( + data={'text': "success"}) + self.app.run( + ['-u', 'user', '-p', 'pass', 'pod', 'create', + '{"name": "asfad"}']) + self.post_mock.assert_called_with( + 'http://localhost:8000/api/v1/pods', + data='{"name": "asfad"}', + headers=self.headers) + + def test_auth_failure(self): + self.post_mock.return_value = fakes.FakeResponse( + data={'text': "login"}) + self.app.run( + ['-u', 'user', '-p', 'pass', 'pod', 'create', + '{"name": "asfad"}']) + self.post_mock.assert_called_once_with( + self.cas_sever, + {'pass': 'pass', 'name': 'user', 'form_id': 'user_login'} + ) + + def test_auth_not_called(self): + self.auth_post = mock.patch( + 'testapiclient.utils.clientmanager.ClientManager.auth').start() + self.app.run(['pod', 'get']) + self.auth_post.assert_not_called() + self.get_mock.assert_called_once_with( + 'http://localhost:8000/api/v1/pods', headers=self.headers) diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_deployresults_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_deployresults_client.py new file mode 100644 index 0000000..03288fe --- /dev/null +++ b/testapi/testapi-client/testapiclient/tests/unit/test_deployresults_client.py @@ -0,0 +1,81 @@ +import json + +from six.moves.urllib import parse +import testtools + +from testapiclient.client import deploy_results +from testapiclient.tests.unit import fakes +from testapiclient.tests.unit import utils +from testapiclient.utils import clientmanager + + +class DeployResultsClientTest(utils.TestCommand): + def setUp(self): + super(DeployResultsClientTest, self).setUp() + self.base_url = parse.urljoin(self.api_url, 'deployresults') + self.deployresult_json = { + 'project_name': 'functest', + 'scenario': 'test-scenario', + 'stop_date': '2018-04-09 13:44:53', + 'case_name': 'test-case', + 'build_tag': 'test-build', + 'version': 'test-version', + 'pod_name': 'test-pod', + 'criteria': 'test-criteria', + 'installer': 'test-installer', + 'start_date': '2018-04-09 13:44:53', + 'details': 'test-details' + } + self.deployresult_id = '5a6dc1089a07c80f3c9f8d62' + self.deployresult_string = json.dumps(self.deployresult_json) + self.deployresult_client = deploy_results.DeployResultsClient() + + +class DeployResultsClientGetTest(DeployResultsClientTest): + + def setUp(self): + super(DeployResultsClientGetTest, self).setUp() + self.deployresults_rsp = {'deployresults': [self.deployresult_json]} + + def test_get(self): + self.get_mock.return_value = fakes.FakeResponse( + data=self.deployresults_rsp) + self.deployresult_client.get() + self.get_mock.assert_called_once_with( + self.base_url, + headers=clientmanager.ClientManager.headers) + + def test_get_search(self): + self.get_mock.return_value = fakes.FakeResponse( + data=self.deployresults_rsp) + self.deployresult_client.get(name='deployresult1') + self.get_mock.assert_called_once_with( + self.base_url + '?name=deployresult1', + headers=clientmanager.ClientManager.headers) + + def test_get_one(self): + self.get_mock.return_value = fakes.FakeResponse( + data=self.deployresult_json) + self.deployresult_client.get_one('2333') + self.get_mock.assert_called_once_with( + self.base_url + '/2333', + headers=clientmanager.ClientManager.headers) + + +class DeployResultsClientCreateTest(DeployResultsClientTest): + + def setUp(self): + super(DeployResultsClientCreateTest, self).setUp() + self.succ_rsp = { + 'href': '{}/{}'.format(self.base_url, self.deployresult_id) + } + + def test_create_success(self): + self.post_mock.return_value = fakes.FakeResponse(data=self.succ_rsp) + self.deployresult_client.create(self.deployresult_json) + self.post_mock.assert_called_once() + + def test_create_failure(self): + with testtools.ExpectedException(Exception, 'Create failed: Error'): + self.post_mock.return_value = utils.FAKE_FAILURE + self.deployresult_client.create(self.deployresult_json) diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_pod_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_pod_client.py new file mode 100644 index 0000000..1df5660 --- /dev/null +++ b/testapi/testapi-client/testapiclient/tests/unit/test_pod_client.py @@ -0,0 +1,89 @@ +import json + +from six.moves.urllib import parse +import testtools + +from testapiclient.client import pods +from testapiclient.tests.unit import fakes +from testapiclient.tests.unit import utils +from testapiclient.utils import clientmanager + + +class PodClientTest(utils.TestCommand): + def setUp(self): + super(PodClientTest, self).setUp() + self.base_url = parse.urljoin(self.api_url, 'pods') + self.pod_json = { + 'role': 'community-ci', + 'name': 'test_pod', + 'details': '', + 'mode': 'metal' + } + self.pod_client = pods.PodsClient() + self.pod_string = json.dumps(self.pod_json) + + +class PodClientGetTest(PodClientTest): + + def setUp(self): + super(PodClientGetTest, self).setUp() + self.pods_rsp = {'pods': [self.pod_json]} + + def test_get(self): + self.get_mock.return_value = fakes.FakeResponse(data=self.pods_rsp) + self.pod_client.get() + self.get_mock.assert_called_once_with( + self.base_url, + headers=clientmanager.ClientManager.headers) + + def test_get_search(self): + self.get_mock.return_value = fakes.FakeResponse(data=self.pods_rsp) + self.pod_client.get(name='pod1') + self.get_mock.assert_called_once_with( + self.base_url + '?name=pod1', + headers=clientmanager.ClientManager.headers) + + def test_get_one(self): + self.get_mock.return_value = fakes.FakeResponse(data=self.pod_json) + self.pod_client.get_one('def') + self.get_mock.assert_called_once_with( + self.base_url + '/def', + headers=clientmanager.ClientManager.headers) + + +class PodClientCreateTest(PodClientTest): + + def setUp(self): + super(PodClientCreateTest, self).setUp() + self.succ_rsp = { + 'href': '{}/{}'.format(self.base_url, self.pod_json.get('name')) + } + + def test_create_success(self): + self.post_mock.return_value = fakes.FakeResponse(data=self.succ_rsp) + self.pod_client.create(self.pod_json) + self.post_mock.assert_called_once() + + def test_create_failure(self): + with testtools.ExpectedException(Exception, 'Create failed: Error'): + self.post_mock.return_value = utils.FAKE_FAILURE + self.pod_client.create(self.pod_json) + + +class PodClientDeleteTest(PodClientTest): + + def setUp(self): + super(PodClientDeleteTest, self).setUp() + + def test_delete_success(self): + self.delete_mock.return_value = fakes.FakeResponse() + self.pod_client.delete('def') + self.delete_mock.assert_called_once_with( + self.base_url + '/def', + data=None, + headers=clientmanager.ClientManager.headers) + + def test_delete_failure(self): + with testtools.ExpectedException(Exception, 'Delete failed: Error'): + self.delete_mock.return_value = utils.FAKE_FAILURE + self.pod_client.delete('def') diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_project_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_project_client.py new file mode 100644 index 0000000..7aa11e6 --- /dev/null +++ b/testapi/testapi-client/testapiclient/tests/unit/test_project_client.py @@ -0,0 +1,111 @@ +import json + +from six.moves.urllib import parse +import testtools + +from testapiclient.client import projects +from testapiclient.tests.unit import fakes +from testapiclient.tests.unit import utils +from testapiclient.utils import clientmanager + + +class ProjectClientTest(utils.TestCommand): + def setUp(self): + super(ProjectClientTest, self).setUp() + self.base_url = parse.urljoin(self.api_url, 'projects') + self.project_json = { + 'description': 'test_description', + 'name': 'test_project', + } + self.project_client = projects.ProjectsClient() + self.project_string = json.dumps(self.project_json) + + +class ProjectClientGetTest(ProjectClientTest): + + def setUp(self): + super(ProjectClientGetTest, self).setUp() + self.projects_rsp = {'projects': [self.project_json]} + + def test_get(self): + self.get_mock.return_value = fakes.FakeResponse( + data=self.projects_rsp) + self.project_client.get() + self.get_mock.assert_called_once_with( + self.base_url, + headers=clientmanager.ClientManager.headers) + + def test_get_search(self): + self.get_mock.return_value = fakes.FakeResponse( + data=self.projects_rsp) + self.project_client.get(name='project1') + self.get_mock.assert_called_once_with( + self.base_url + '?name=project1', + headers=clientmanager.ClientManager.headers) + + def test_get_one(self): + self.get_mock.return_value = fakes.FakeResponse( + data=self.project_json) + self.project_client.get_one('def') + self.get_mock.assert_called_once_with( + self.base_url + '/def', + headers=clientmanager.ClientManager.headers) + + +class ProjectClientCreateTest(ProjectClientTest): + + def setUp(self): + super(ProjectClientCreateTest, self).setUp() + self.succ_rsp = { + 'href': '{}/{}'.format( + self.base_url, self.project_json.get('name')) + } + + def test_create_success(self): + self.post_mock.return_value = fakes.FakeResponse( + data=self.succ_rsp) + self.project_client.create(self.project_json) + self.post_mock.assert_called_once() + + def test_create_failure(self): + with testtools.ExpectedException(Exception, 'Create failed: Error'): + self.post_mock.return_value = utils.FAKE_FAILURE + self.project_client.create(self.project_json) + + +class ProjectClientDeleteTest(ProjectClientTest): + + def setUp(self): + super(ProjectClientDeleteTest, self).setUp() + + def test_delete_success(self): + self.delete_mock.return_value = fakes.FakeResponse() + self.project_client.delete('def') + self.delete_mock.assert_called_once_with( + self.base_url + '/def', + data=None, + headers=clientmanager.ClientManager.headers) + + def test_delete_failure(self): + with testtools.ExpectedException(Exception, 'Delete failed: Error'): + self.delete_mock.return_value = utils.FAKE_FAILURE + self.project_client.delete('def') + + +class ProjectClientUpdateTest(ProjectClientTest): + + def setUp(self): + super(ProjectClientUpdateTest, self).setUp() + + def test_update_success(self): + self.put_mock.return_value = fakes.FakeResponse() + self.project_client.update('def', self.project_json) + self.put_mock.assert_called_once_with( + self.base_url + '/def', + data=self.project_string, + headers=clientmanager.ClientManager.headers) + + def test_update_failure(self): + with testtools.ExpectedException(Exception, 'Update failed: Error'): + self.put_mock.return_value = utils.FAKE_FAILURE + self.project_client.update('def', self.project_json) diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_results.py b/testapi/testapi-client/testapiclient/tests/unit/test_results.py new file mode 100644 index 0000000..83bcc9f --- /dev/null +++ b/testapi/testapi-client/testapiclient/tests/unit/test_results.py @@ -0,0 +1,98 @@ +import json + +from mock import mock +from six.moves.urllib import parse +import testtools + +from testapiclient.cli import results +from testapiclient.tests.unit import fakes +from testapiclient.tests.unit import utils +from testapiclient.utils import clientmanager + + +class ResultTest(utils.TestCommand): + def setUp(self): + super(ResultTest, self).setUp() + self.base_url = parse.urljoin(self.api_url, 'results') + self.result_json = { + 'project_name': 'functest', + 'scenario': 'test-scenario', + 'stop_date': '2018-04-09 13:44:53', + 'case_name': 'test-case', + 'build_tag': 'test-build', + 'version': 'test-version', + 'pod_name': 'test-pod', + 'criteria': 'test-criteria', + 'installer': 'test-installer', + 'start_date': '2018-04-09 13:44:53', + 'details': 'test-details' + } + self.result_string = json.dumps(self.result_json) + + +class ResultGetTest(ResultTest): + + def setUp(self): + super(ResultGetTest, self).setUp() + self.results_rsp = {'results': [self.result_json]} + + def test_get(self): + self.get_mock.return_value = fakes.FakeResponse(data=self.results_rsp) + result_get = results.ResultGet(self.app, mock.Mock()) + args = ['-case', 'dfs'] + verifies = [('case', 'dfs')] + parsed_args = self.check_parser(result_get, args, verifies) + result_get.take_action(parsed_args) + self.get_mock.assert_called_once_with( + self.base_url + '?case=dfs', + headers=clientmanager.ClientManager.headers) + + def test_get_all(self): + self.get_mock.return_value = fakes.FakeResponse(data=self.results_rsp) + result_get = results.ResultGet(self.app, mock.Mock()) + args = [] + verifies = [] + parsed_args = self.check_parser(result_get, args, verifies) + result_get.take_action(parsed_args) + self.get_mock.assert_called_once_with( + self.base_url, + headers=clientmanager.ClientManager.headers) + + def test_get_one(self): + self.get_mock.return_value = fakes.FakeResponse(data=self.result_json) + result_get_one = results.ResultGetOne(self.app, mock.Mock()) + args = ['def'] + verifies = [('result_id', 'def')] + parsed_args = self.check_parser(result_get_one, args, verifies) + result_get_one.take_action(parsed_args) + self.get_mock.assert_called_once_with( + self.base_url + '/def', + headers=clientmanager.ClientManager.headers) + + +class ResultCreateTest(ResultTest): + + def setUp(self): + super(ResultCreateTest, self).setUp() + + def test_create_success(self): + succ_rsp = { + 'href': '{}/{}'.format(self.base_url, + self.result_json.get('project_name')) + } + self.post_mock.return_value = fakes.FakeResponse(data=succ_rsp) + result_create = results.ResultCreate(self.app, mock.Mock()) + args = [self.result_string] + verifies = [('result', self.result_json)] + parsed_args = self.check_parser(result_create, args, verifies) + result_create.take_action(parsed_args) + self.post_mock.assert_called_once() + + def test_create_failure(self): + with testtools.ExpectedException(Exception, 'Create failed: Error'): + self.post_mock.return_value = utils.FAKE_FAILURE + result_create = results.ResultCreate(self.app, mock.Mock()) + args = [self.result_string] + verifies = [('result', self.result_json)] + parsed_args = self.check_parser(result_create, args, verifies) + result_create.take_action(parsed_args) diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_results_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_results_client.py new file mode 100644 index 0000000..ae677f7 --- /dev/null +++ b/testapi/testapi-client/testapiclient/tests/unit/test_results_client.py @@ -0,0 +1,78 @@ +import json + +from six.moves.urllib import parse +import testtools + +from testapiclient.client import results +from testapiclient.tests.unit import fakes +from testapiclient.tests.unit import utils +from testapiclient.utils import clientmanager + + +class ResultClientTest(utils.TestCommand): + def setUp(self): + super(ResultClientTest, self).setUp() + self.base_url = parse.urljoin(self.api_url, 'results') + self.result_json = { + 'project_name': 'functest', + 'scenario': 'test-scenario', + 'stop_date': '2018-04-09 13:44:53', + 'case_name': 'test-case', + 'build_tag': 'test-build', + 'version': 'test-version', + 'pod_name': 'test-pod', + 'criteria': 'test-criteria', + 'installer': 'test-installer', + 'start_date': '2018-04-09 13:44:53', + 'details': 'test-details' + } + self.result_id = '5a6dc1089a07c80f3c9f8d62' + self.result_string = json.dumps(self.result_json) + self.result_client = results.ResultsClient() + + +class ResultClientGetTest(ResultClientTest): + + def setUp(self): + super(ResultClientGetTest, self).setUp() + self.results_rsp = {'results': [self.result_json]} + + def test_get(self): + self.get_mock.return_value = fakes.FakeResponse(data=self.results_rsp) + self.result_client.get() + self.get_mock.assert_called_once_with( + self.base_url, + headers=clientmanager.ClientManager.headers) + + def test_get_search(self): + self.get_mock.return_value = fakes.FakeResponse(data=self.results_rsp) + self.result_client.get(name='result1') + self.get_mock.assert_called_once_with( + self.base_url + '?name=result1', + headers=clientmanager.ClientManager.headers) + + def test_get_one(self): + self.get_mock.return_value = fakes.FakeResponse(data=self.result_json) + self.result_client.get_one('2333') + self.get_mock.assert_called_once_with( + self.base_url + '/2333', + headers=clientmanager.ClientManager.headers) + + +class ResultClientCreateTest(ResultClientTest): + + def setUp(self): + super(ResultClientCreateTest, self).setUp() + self.succ_rsp = { + 'href': '{}/{}'.format(self.base_url, self.result_id) + } + + def test_create_success(self): + self.post_mock.return_value = fakes.FakeResponse(data=self.succ_rsp) + self.result_client.create(self.result_json) + self.post_mock.assert_called_once() + + def test_create_failure(self): + with testtools.ExpectedException(Exception, 'Create failed: Error'): + self.post_mock.return_value = utils.FAKE_FAILURE + self.result_client.create(self.result_json) diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_client.py new file mode 100644 index 0000000..6e9e0fa --- /dev/null +++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_client.py @@ -0,0 +1,104 @@ +import json + +from six.moves.urllib import parse +import testtools + +from testapiclient.client import scenarios +from testapiclient.tests.unit import fakes +from testapiclient.tests.unit import utils +from testapiclient.utils import clientmanager + + +class ScenarioClientTest(utils.TestCommand): + def setUp(self): + super(ScenarioClientTest, self).setUp() + self.base_url = parse.urljoin(self.api_url, 'scenarios') + self.scenario_json = { + "installers": [], + "name": "test_scenario" + } + self.scenario_client = scenarios.ScenariosClient() + self.scenario_string = json.dumps(self.scenario_json) + + +class ScenarioClientGetTest(ScenarioClientTest): + + def setUp(self): + super(ScenarioClientGetTest, self).setUp() + self.scenarios_rsp = {'scenarios': [self.scenario_json]} + + def test_get(self): + self.get_mock.return_value = fakes.FakeResponse( + data=self.scenarios_rsp) + self.scenario_client.get() + self.get_mock.assert_called_once_with( + self.base_url, + headers=clientmanager.ClientManager.headers) + + def test_get_one(self): + self.get_mock.return_value = fakes.FakeResponse( + data=self.scenario_json) + self.scenario_client.get_one('def') + self.get_mock.assert_called_once_with( + self.base_url + '/def', + headers=clientmanager.ClientManager.headers) + + +class ScenarioClientCreateTest(ScenarioClientTest): + + def setUp(self): + super(ScenarioClientCreateTest, self).setUp() + self.succ_rsp = { + 'href': '{}/{}'.format( + self.base_url, self.scenario_json.get('name')) + } + + def test_create_success(self): + self.post_mock.return_value = fakes.FakeResponse( + data=self.succ_rsp) + self.scenario_client.create(self.scenario_json) + self.post_mock.assert_called_once() + + def test_create_failure(self): + with testtools.ExpectedException(Exception, 'Create failed: Error'): + self.post_mock.return_value = utils.FAKE_FAILURE + self.scenario_client.create(self.scenario_json) + + +class ScenarioClientDeleteTest(ScenarioClientTest): + + def setUp(self): + super(ScenarioClientDeleteTest, self).setUp() + + def test_delete_success(self): + self.delete_mock.return_value = fakes.FakeResponse() + self.scenario_client.delete('def') + self.delete_mock.assert_called_once_with( + self.base_url + '/def', + data=None, + headers=clientmanager.ClientManager.headers) + + def test_delete_failure(self): + with testtools.ExpectedException(Exception, 'Delete failed: Error'): + self.delete_mock.return_value = utils.FAKE_FAILURE + self.scenario_client.delete('def') + + +class ScenarioClientUpdateTest(ScenarioClientTest): + + def setUp(self): + super(ScenarioClientUpdateTest, self).setUp() + + def test_update_success(self): + self.put_mock.return_value = fakes.FakeResponse() + self.scenario_client.update( + 'def', self.scenario_json) + self.put_mock.assert_called_once_with( + self.base_url + '/def', + data=self.scenario_string, + headers=clientmanager.ClientManager.headers) + + def test_update_failure(self): + with testtools.ExpectedException(Exception, 'Update failed: Error'): + self.put_mock.return_value = utils.FAKE_FAILURE + self.scenario_client.update('def', self.scenario_json) diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_custom_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_custom_client.py new file mode 100644 index 0000000..7c6d62c --- /dev/null +++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_custom_client.py @@ -0,0 +1,106 @@ +from six.moves.urllib import parse +import testtools + +from testapiclient.client import scenarios +from testapiclient.tests.unit import fakes +from testapiclient.tests.unit import utils + + +class CustomClientTest(utils.TestCommand): + def setUp(self): + super(CustomClientTest, self).setUp() + self.scenario_name = 'scenrio1' + self.base_url = parse.urljoin( + self.api_url, + 'scenarios/{}/customs'.format(self.scenario_name)) + self.custom_raw = 'custom' + self.custom_input = ['custom'] + self.installer_name = 'installer' + self.version_name = 'version' + self.project_name = 'project' + self.custom_client = scenarios.CustomsClient() + + +class CustomClientCreateTest(CustomClientTest): + + def setUp(self): + super(CustomClientCreateTest, self).setUp() + self.succ_rsp = { + 'href': '{}/{}'.format( + self.base_url, self.scenario_name) + } + + def test_create_success(self): + self.post_mock.return_value = fakes.FakeResponse( + data=self.succ_rsp) + self.custom_client.create( + self.scenario_name, self.installer_name, + self.version_name, self.project_name, + self.custom_raw) + self.post_mock.assert_called_once() + + def test_create_failure(self): + with testtools.ExpectedException(Exception, 'Create failed: Error'): + self.post_mock.return_value = utils.FAKE_FAILURE + self.custom_client.create( + self.scenario_name, self.installer_name, + self.version_name, self.project_name, + self.custom_raw) + + +class CustomClientDeleteTest(CustomClientTest): + + def setUp(self): + super(CustomClientDeleteTest, self).setUp() + + def test_delete_success(self): + self.delete_mock.return_value = fakes.FakeResponse() + self.custom_client.delete( + self.scenario_name, self.installer_name, + self.version_name, self.project_name, + self.custom_raw) + kall = self.delete_mock.call_args + args, kwargs = kall + self.assert_url( + args[0], + self.base_url + + '?installer=installer&version=version&project=project') + + def test_delete_failure(self): + with testtools.ExpectedException(Exception, 'Delete failed: Error'): + self.delete_mock.return_value = utils.FAKE_FAILURE + self.custom_client.delete( + self.scenario_name, self.installer_name, + self.version_name, self.project_name, + self.custom_raw) + + +class CustomClientUpdateTest(CustomClientTest): + + def setUp(self): + super(CustomClientUpdateTest, self).setUp() + + def test_update_success(self): + self.put_mock.return_value = fakes.FakeResponse() + self.custom_client.update( + self.scenario_name, + self.installer_name, + self.version_name, + self.project_name, + self.custom_raw) + kall = self.put_mock.call_args + args, kwargs = kall + self.assert_url( + args[0], + self.base_url + + '?installer=installer&version=version&project=project') + + def test_update_failure(self): + with testtools.ExpectedException(Exception, 'Update failed: Error'): + self.put_mock.return_value = utils.FAKE_FAILURE + self.custom_client.update( + self.scenario_name, + self.installer_name, + self.version_name, + self.project_name, + self.custom_raw) diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_installer_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_installer_client.py new file mode 100644 index 0000000..71ba150 --- /dev/null +++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_installer_client.py @@ -0,0 +1,86 @@ +import json + +from six.moves.urllib import parse +import testtools + +from testapiclient.client import scenarios +from testapiclient.tests.unit import fakes +from testapiclient.tests.unit import utils +from testapiclient.utils import clientmanager + + +class InstallerClientTest(utils.TestCommand): + def setUp(self): + super(InstallerClientTest, self).setUp() + self.scenario_name = 'scenrio1' + self.base_url = parse.urljoin( + self.api_url, + 'scenarios/{}/installers'.format(self.scenario_name)) + self.installer_json = { + 'versions': [], + 'installer': 'test-installer', + } + self.installer_client = scenarios.InstallersClient() + self.installer_string = json.dumps(self.installer_json) + + +class InstallerClientCreateTest(InstallerClientTest): + + def setUp(self): + super(InstallerClientCreateTest, self).setUp() + self.succ_rsp = { + 'href': '{}/{}'.format( + self.base_url, self.installer_json.get('name')) + } + + def test_create_success(self): + self.post_mock.return_value = fakes.FakeResponse( + data=self.succ_rsp) + self.installer_client.create(self.scenario_name, self.installer_json) + self.post_mock.assert_called_once() + + def test_create_failure(self): + with testtools.ExpectedException(Exception, 'Create failed: Error'): + self.post_mock.return_value = utils.FAKE_FAILURE + self.installer_client.create( + self.scenario_name, self.installer_json) + + +class InstallerClientDeleteTest(InstallerClientTest): + + def setUp(self): + super(InstallerClientDeleteTest, self).setUp() + + def test_delete_success(self): + self.delete_mock.return_value = fakes.FakeResponse() + self.installer_client.delete(self.scenario_name, 'def') + self.delete_mock.assert_called_once_with( + self.base_url, + data=json.dumps(['def']), + headers=clientmanager.ClientManager.headers) + + def test_delete_failure(self): + with testtools.ExpectedException(Exception, 'Delete failed: Error'): + self.delete_mock.return_value = utils.FAKE_FAILURE + self.installer_client.delete(self.scenario_name, 'def') + + +class InstallerClientUpdateTest(InstallerClientTest): + + def setUp(self): + super(InstallerClientUpdateTest, self).setUp() + + def test_update_success(self): + self.put_mock.return_value = fakes.FakeResponse() + self.installer_client.update( + self.scenario_name, + self.installer_json) + self.put_mock.assert_called_once_with( + self.base_url, + data=self.installer_string, + headers=clientmanager.ClientManager.headers) + + def test_update_failure(self): + with testtools.ExpectedException(Exception, 'Update failed: Error'): + self.put_mock.return_value = utils.FAKE_FAILURE + self.installer_client.update('def', self.installer_json) diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_project_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_project_client.py new file mode 100644 index 0000000..f8c3d60 --- /dev/null +++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_project_client.py @@ -0,0 +1,104 @@ +import json + +from six.moves.urllib import parse +import testtools + +from testapiclient.client import scenarios +from testapiclient.tests.unit import fakes +from testapiclient.tests.unit import utils + + +class ProjectClientTest(utils.TestCommand): + def setUp(self): + super(ProjectClientTest, self).setUp() + self.scenario_name = 'scenrio1' + self.base_url = parse.urljoin( + self.api_url, + 'scenarios/{}/projects'.format(self.scenario_name)) + self.project_json = { + 'trust_indicators': [], + 'project': 'test-project', + 'scores': [], + 'customs': [] + } + self.installer_name = 'installer' + self.version_name = 'version' + self.project_client = scenarios.ProjectsClient() + self.project_string = json.dumps(self.project_json) + + +class ProjectClientCreateTest(ProjectClientTest): + + def setUp(self): + super(ProjectClientCreateTest, self).setUp() + self.succ_rsp = { + 'href': '{}/{}'.format( + self.base_url, self.project_json.get('name')) + } + + def test_create_success(self): + self.post_mock.return_value = fakes.FakeResponse( + data=self.succ_rsp) + self.project_client.create( + self.scenario_name, self.installer_name, + self.version_name, self.project_json) + self.post_mock.assert_called_once() + + def test_create_failure(self): + with testtools.ExpectedException(Exception, 'Create failed: Error'): + self.post_mock.return_value = utils.FAKE_FAILURE + self.project_client.create( + self.scenario_name, self.installer_name, + self.version_name, self.project_json) + + +class ProjectClientDeleteTest(ProjectClientTest): + + def setUp(self): + super(ProjectClientDeleteTest, self).setUp() + + def test_delete_success(self): + self.delete_mock.return_value = fakes.FakeResponse() + self.project_client.delete( + self.scenario_name, self.installer_name, + self.version_name, 'def') + kall = self.delete_mock.call_args + args, kwargs = kall + self.assert_url( + args[0], + self.base_url + '?installer=installer&version=version') + + def test_delete_failure(self): + with testtools.ExpectedException(Exception, 'Delete failed: Error'): + self.delete_mock.return_value = utils.FAKE_FAILURE + self.project_client.delete( + self.scenario_name, self.installer_name, + self.version_name, 'def') + + +class ProjectClientUpdateTest(ProjectClientTest): + + def setUp(self): + super(ProjectClientUpdateTest, self).setUp() + + def test_update_success(self): + self.put_mock.return_value = fakes.FakeResponse() + self.project_client.update( + self.scenario_name, + self.installer_name, + self.version_name, + self.project_json) + kall = self.put_mock.call_args + args, kwargs = kall + self.assert_url( + args[0], + self.base_url + '?installer=installer&version=version') + + def test_update_failure(self): + with testtools.ExpectedException(Exception, 'Update failed: Error'): + self.put_mock.return_value = utils.FAKE_FAILURE + self.project_client.update( + self.scenario_name, + self.installer_name, + self.version_name, + self.project_json) diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_score_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_score_client.py new file mode 100644 index 0000000..beebd47 --- /dev/null +++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_score_client.py @@ -0,0 +1,53 @@ +import json + +from six.moves.urllib import parse +import testtools + +from testapiclient.client import scenarios +from testapiclient.tests.unit import fakes +from testapiclient.tests.unit import utils + + +class ScoreClientTest(utils.TestCommand): + def setUp(self): + super(ScoreClientTest, self).setUp() + self.scenario_name = 'scenrio1' + self.base_url = parse.urljoin( + self.api_url, + 'scenarios/{}/scores'.format(self.scenario_name)) + self.score_json = { + 'score': 'test_score1', + 'date': '2018/01/2' + } + self.installer_name = 'installer' + self.version_name = 'version' + self.project_name = 'project' + self.score_client = scenarios.ScoresClient() + self.score_string = json.dumps(self.score_json) + + +class ScoreClientCreateTest(ScoreClientTest): + + def setUp(self): + super(ScoreClientCreateTest, self).setUp() + self.succ_rsp = { + 'href': '{}/{}'.format( + self.base_url, self.score_json.get('name')) + } + + def test_create_success(self): + self.post_mock.return_value = fakes.FakeResponse( + data=self.succ_rsp) + self.score_client.create( + self.scenario_name, self.installer_name, + self.version_name, self.project_name, + self.score_json) + self.post_mock.assert_called_once() + + def test_create_failure(self): + with testtools.ExpectedException(Exception, 'Create failed: Error'): + self.post_mock.return_value = utils.FAKE_FAILURE + self.score_client.create( + self.scenario_name, self.installer_name, + self.version_name, self.project_name, + self.score_json) diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_trust_indicator_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_trust_indicator_client.py new file mode 100644 index 0000000..e44e2d2 --- /dev/null +++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_trust_indicator_client.py @@ -0,0 +1,53 @@ +import json + +from six.moves.urllib import parse +import testtools + +from testapiclient.client import scenarios +from testapiclient.tests.unit import fakes +from testapiclient.tests.unit import utils + + +class TrustIndicatorClientTest(utils.TestCommand): + def setUp(self): + super(TrustIndicatorClientTest, self).setUp() + self.scenario_name = 'scenrio1' + self.base_url = parse.urljoin( + self.api_url, + 'scenarios/{}/trust_indicators'.format(self.scenario_name)) + self.trust_indicator_json = { + 'status': 'test_status', + 'date': '2018/01/2' + } + self.installer_name = 'installer' + self.version_name = 'version' + self.project_name = 'project' + self.trust_indicator_client = scenarios.TrustIndicatorsClient() + self.trust_indicator_string = json.dumps(self.trust_indicator_json) + + +class TrustIndicatorClientCreateTest(TrustIndicatorClientTest): + + def setUp(self): + super(TrustIndicatorClientCreateTest, self).setUp() + self.succ_rsp = { + 'href': '{}/{}'.format( + self.base_url, self.trust_indicator_json.get('name')) + } + + def test_create_success(self): + self.post_mock.return_value = fakes.FakeResponse( + data=self.succ_rsp) + self.trust_indicator_client.create( + self.scenario_name, self.installer_name, + self.version_name, self.project_name, + self.trust_indicator_json) + self.post_mock.assert_called_once() + + def test_create_failure(self): + with testtools.ExpectedException(Exception, 'Create failed: Error'): + self.post_mock.return_value = utils.FAKE_FAILURE + self.trust_indicator_client.create( + self.scenario_name, self.installer_name, + self.version_name, self.project_name, + self.trust_indicator_json) diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_version_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_version_client.py new file mode 100644 index 0000000..1ae2409 --- /dev/null +++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_version_client.py @@ -0,0 +1,96 @@ +import json + +from six.moves.urllib import parse +import testtools + +from testapiclient.client import scenarios +from testapiclient.tests.unit import fakes +from testapiclient.tests.unit import utils +from testapiclient.utils import clientmanager + + +class VersionClientTest(utils.TestCommand): + def setUp(self): + super(VersionClientTest, self).setUp() + self.scenario_name = 'scenrio1' + self.base_url = parse.urljoin( + self.api_url, + 'scenarios/{}/versions'.format(self.scenario_name)) + self.version_json = { + 'projects': [], + 'version': 'test-version', + 'owner': 'test_owner' + } + self.installer_name = 'installer' + self.version_client = scenarios.VersionsClient() + self.version_string = json.dumps(self.version_json) + + +class VersionClientCreateTest(VersionClientTest): + + def setUp(self): + super(VersionClientCreateTest, self).setUp() + self.succ_rsp = { + 'href': '{}/{}'.format( + self.base_url, self.version_json.get('name')) + } + + def test_create_success(self): + self.post_mock.return_value = fakes.FakeResponse( + data=self.succ_rsp) + self.version_client.create( + self.scenario_name, self.installer_name, self.version_json) + self.post_mock.assert_called_once() + + def test_create_failure(self): + with testtools.ExpectedException(Exception, 'Create failed: Error'): + self.post_mock.return_value = utils.FAKE_FAILURE + self.version_client.create( + self.scenario_name, self.installer_name, self.version_json) + + +class VersionClientDeleteTest(VersionClientTest): + + def setUp(self): + super(VersionClientDeleteTest, self).setUp() + + def test_delete_success(self): + self.delete_mock.return_value = fakes.FakeResponse() + self.version_client.delete( + self.scenario_name, self.installer_name, 'def') + kall = self.delete_mock.call_args + args, kwargs = kall + self.assert_url( + args[0], + self.base_url + '?installer=installer') + + def test_delete_failure(self): + with testtools.ExpectedException(Exception, 'Delete failed: Error'): + self.delete_mock.return_value = utils.FAKE_FAILURE + self.version_client.delete( + self.scenario_name, self.installer_name, 'def') + + +class VersionClientUpdateTest(VersionClientTest): + + def setUp(self): + super(VersionClientUpdateTest, self).setUp() + + def test_update_success(self): + self.put_mock.return_value = fakes.FakeResponse() + self.version_client.update( + self.scenario_name, + self.installer_name, + self.version_json) + self.put_mock.assert_called_once_with( + self.base_url + '?installer=installer', + data=self.version_string, + headers=clientmanager.ClientManager.headers) + + def test_update_failure(self): + with testtools.ExpectedException(Exception, 'Update failed: Error'): + self.put_mock.return_value = utils.FAKE_FAILURE + self.version_client.update( + self.scenario_name, + self.installer_name, + self.version_json) diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_testcase_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_testcase_client.py new file mode 100644 index 0000000..d80ae27 --- /dev/null +++ b/testapi/testapi-client/testapiclient/tests/unit/test_testcase_client.py @@ -0,0 +1,118 @@ +import json + +from six.moves.urllib import parse +import testtools + +from testapiclient.client import testcases +from testapiclient.tests.unit import fakes +from testapiclient.tests.unit import utils +from testapiclient.utils import clientmanager + + +class TestcaseClientTest(utils.TestCommand): + def setUp(self): + super(TestcaseClientTest, self).setUp() + self.base_url = parse.urljoin(self.api_url, 'projects/{}/cases') + self.project_name = 'functest' + self.testcase_json = { + 'run': '', + 'name': 'test-case', + 'ci_loop': '', + 'tags': '', + 'url': '', + 'blocking': '', + 'domains': '', + 'dependencies': '', + 'version': '', + 'criteria': '', + 'tier': '', + 'trust': '', + 'catalog_description': '', + 'description': '' + } + self.testcase_client = testcases.TestcasesClient() + self.testcase_string = json.dumps(self.testcase_json) + + +class TestcaseClientGetTest(TestcaseClientTest): + + def setUp(self): + super(TestcaseClientGetTest, self).setUp() + self.testcases_rsp = {'testcases': [self.testcase_json]} + + def test_get(self): + self.get_mock.return_value = fakes.FakeResponse( + data=self.testcases_rsp) + self.testcase_client.get(self.project_name) + self.get_mock.assert_called_once_with( + self.base_url.format(self.project_name), + headers=clientmanager.ClientManager.headers) + + def test_get_one(self): + self.get_mock.return_value = fakes.FakeResponse( + data=self.testcase_json) + self.testcase_client.get_one(self.project_name, 'def') + self.get_mock.assert_called_once_with( + self.base_url.format(self.project_name) + '/def', + headers=clientmanager.ClientManager.headers) + + +class TestcaseClientCreateTest(TestcaseClientTest): + + def setUp(self): + super(TestcaseClientCreateTest, self).setUp() + self.succ_rsp = { + 'href': '{}/{}'.format( + self.base_url, self.testcase_json.get('name')) + } + + def test_create_success(self): + self.post_mock.return_value = fakes.FakeResponse( + data=self.succ_rsp) + self.testcase_client.create(self.project_name, self.testcase_json) + self.post_mock.assert_called_once() + + def test_create_failure(self): + with testtools.ExpectedException(Exception, 'Create failed: Error'): + self.post_mock.return_value = utils.FAKE_FAILURE + self.testcase_client.create(self.project_name, self.testcase_json) + + +class TestcaseClientDeleteTest(TestcaseClientTest): + + def setUp(self): + super(TestcaseClientDeleteTest, self).setUp() + + def test_delete_success(self): + self.delete_mock.return_value = fakes.FakeResponse() + self.testcase_client.delete(self.project_name, 'def') + self.delete_mock.assert_called_once_with( + self.base_url.format(self.project_name) + '/def', + data=None, + headers=clientmanager.ClientManager.headers) + + def test_delete_failure(self): + with testtools.ExpectedException(Exception, 'Delete failed: Error'): + self.delete_mock.return_value = utils.FAKE_FAILURE + self.testcase_client.delete(self.project_name, 'def') + + +class TestcaseClientUpdateTest(TestcaseClientTest): + + def setUp(self): + super(TestcaseClientUpdateTest, self).setUp() + + def test_update_success(self): + self.put_mock.return_value = fakes.FakeResponse() + self.testcase_client.update( + self.project_name, 'def', self.testcase_json) + self.put_mock.assert_called_once_with( + self.base_url.format(self.project_name) + '/def', + data=self.testcase_string, + headers=clientmanager.ClientManager.headers) + + def test_update_failure(self): + with testtools.ExpectedException(Exception, 'Update failed: Error'): + self.put_mock.return_value = utils.FAKE_FAILURE + self.testcase_client.update( + self.project_name, 'def', self.testcase_json) diff --git a/testapi/testapi-client/testapiclient/tests/unit/utils.py b/testapi/testapi-client/testapiclient/tests/unit/utils.py index 21f98c4..c59aadd 100644 --- a/testapi/testapi-client/testapiclient/tests/unit/utils.py +++ b/testapi/testapi-client/testapiclient/tests/unit/utils.py @@ -19,7 +19,7 @@ class TestCommand(testtools.TestCase): def setUp(self): super(TestCommand, self).setUp() - env_variables = { + self.env_variables = { 'testapi_url': 'http://localhost:8000/api/v1', 'testapi_cas_auth_url': ( @@ -29,7 +29,7 @@ class TestCommand(testtools.TestCase): 'testapi_cas_signin_return': '/auth/signin_return' } self.config_mock = mock.patch.dict( - 'os.environ', env_variables).start() + 'os.environ', self.env_variables).start() self.fake_stdout = fakes.FakeStdout() self.fake_log = fakes.FakeLog() self.app = fakes.FakeApp(self.fake_stdout, self.fake_log) diff --git a/testapi/testapi-client/testapiclient/utils/clientmanager.py b/testapi/testapi-client/testapiclient/utils/clientmanager.py index 8858819..cbfd723 100644 --- a/testapi/testapi-client/testapiclient/utils/clientmanager.py +++ b/testapi/testapi-client/testapiclient/utils/clientmanager.py @@ -10,7 +10,9 @@ LOG = logging.getLogger(__name__) class ClientManager(object): - headers = {'Content-type': 'application/json', 'Accept': 'text/plain'} + headers = { + 'Content-type': 'application/json', + 'Accept': 'text/plain'} def __init__(self, cli_options=None): self.cli_options = cli_options @@ -49,6 +51,8 @@ class ClientManager(object): headers=self.headers)) def post(self, url, data): + if 'results' in url or 'deployresults' in url: + self.headers['X-Auth-Token'] = os.environ.get('testapi_token') return self._parse_response('Create', self._request('post', url, data=json.dumps(data), |