summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--INFO.yaml47
-rw-r--r--reporting/3rd_party/html/colorado.html (renamed from reporting/html/colorado.html)0
-rw-r--r--reporting/3rd_party/html/danube.html (renamed from reporting/html/danube.html)0
-rw-r--r--reporting/3rd_party/html/elements.html (renamed from reporting/html/elements.html)0
-rw-r--r--reporting/3rd_party/html/euphrates.html (renamed from reporting/html/euphrates.html)0
-rw-r--r--reporting/3rd_party/html/fraser.html (renamed from reporting/html/fraser.html)0
-rw-r--r--reporting/3rd_party/html/functest.html (renamed from reporting/html/functest.html)0
-rw-r--r--reporting/3rd_party/html/generic.html (renamed from reporting/html/generic.html)0
-rw-r--r--reporting/3rd_party/html/index.html (renamed from reporting/html/index.html)0
-rw-r--r--reporting/3rd_party/html/master.html (renamed from reporting/html/master.html)0
-rw-r--r--reporting/css/default.css4
-rwxr-xr-xreporting/docker/reporting.sh7
-rw-r--r--reporting/js/gauge.js4
-rw-r--r--reporting/reporting/bottlenecks/reporting-status.py6
-rwxr-xr-xreporting/reporting/functest/reporting-status.py127
-rw-r--r--reporting/reporting/functest/template/index-status-tmpl.html25
-rw-r--r--reporting/reporting/functest/testCase.py76
-rw-r--r--reporting/reporting/reporting.yaml4
-rw-r--r--reporting/reporting/vsperf/reporting-status.py2
-rw-r--r--testapi/3rd_party/static/testapi-ui/assets/css/style.css49
-rw-r--r--testapi/docker/Dockerfile7
-rw-r--r--testapi/docs/developer/devguide/images/CAS-sequence.jpgbin0 -> 11785 bytes
-rw-r--r--testapi/docs/developer/devguide/testapi-client-import.rst974
-rw-r--r--testapi/docs/developer/devguide/testapi-client.rst858
-rw-r--r--testapi/docs/developer/devguide/web-portal.rst114
-rw-r--r--testapi/docs/internship/webportal.rst169
-rw-r--r--testapi/opnfv_testapi/common/check.py12
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/authenticateFalseSpec.js76
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/deployResultsControllerSpec.js2
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/podsControllerSpec.js36
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js54
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/resultsControllerSpec.js4
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/scenarioControllerSpec.js45
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/scenariosControllerSpec.js42
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/testCasesControllerSpec.js25
-rw-r--r--testapi/opnfv_testapi/ui/Gruntfile.js16
-rw-r--r--testapi/opnfv_testapi/ui/components/pods/pods.html16
-rw-r--r--testapi/opnfv_testapi/ui/components/pods/podsController.js39
-rw-r--r--testapi/opnfv_testapi/ui/components/projects/project/testCases/testCases.html16
-rw-r--r--testapi/opnfv_testapi/ui/components/projects/project/testCases/testCasesController.js68
-rw-r--r--testapi/opnfv_testapi/ui/components/projects/projects.html16
-rw-r--r--testapi/opnfv_testapi/ui/components/projects/projectsController.js60
-rw-r--r--testapi/opnfv_testapi/ui/components/scenarios/scenario/scenario.html16
-rw-r--r--testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js93
-rw-r--r--testapi/opnfv_testapi/ui/components/scenarios/scenarios.html16
-rw-r--r--testapi/opnfv_testapi/ui/components/scenarios/scenariosController.js74
-rw-r--r--testapi/opnfv_testapi/ui/package.json1
-rw-r--r--testapi/requirements.txt3
-rw-r--r--testapi/testapi-client/etc/client.creds3
-rw-r--r--testapi/testapi-client/setup.cfg4
-rw-r--r--testapi/testapi-client/testapiclient/cli/deployresults.py12
-rw-r--r--testapi/testapi-client/testapiclient/cli/pods.py12
-rw-r--r--testapi/testapi-client/testapiclient/cli/projects.py15
-rw-r--r--testapi/testapi-client/testapiclient/cli/results.py97
-rw-r--r--testapi/testapi-client/testapiclient/cli/scenarios.py147
-rw-r--r--testapi/testapi-client/testapiclient/cli/testcases.py19
-rw-r--r--testapi/testapi-client/testapiclient/client/__init__.py0
-rw-r--r--testapi/testapi-client/testapiclient/client/base.py23
-rw-r--r--testapi/testapi-client/testapiclient/client/deploy_results.py28
-rw-r--r--testapi/testapi-client/testapiclient/client/pods.py31
-rw-r--r--testapi/testapi-client/testapiclient/client/projects.py35
-rw-r--r--testapi/testapi-client/testapiclient/client/results.py28
-rw-r--r--testapi/testapi-client/testapiclient/client/scenarios.py177
-rw-r--r--testapi/testapi-client/testapiclient/client/testcases.py36
-rw-r--r--testapi/testapi-client/testapiclient/models/__init__.py0
-rw-r--r--testapi/testapi-client/testapiclient/models/deployresult.py17
-rw-r--r--testapi/testapi-client/testapiclient/models/pods.py6
-rw-r--r--testapi/testapi-client/testapiclient/models/project.py4
-rw-r--r--testapi/testapi-client/testapiclient/models/result.py16
-rw-r--r--testapi/testapi-client/testapiclient/models/scenario.py37
-rw-r--r--testapi/testapi-client/testapiclient/models/testcase.py20
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_app.py50
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_deployresults_client.py81
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_pod_client.py89
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_project_client.py111
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_results.py98
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_results_client.py78
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_client.py104
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_custom_client.py106
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_installer_client.py86
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_project_client.py104
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_score_client.py53
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_trust_indicator_client.py53
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_version_client.py96
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_testcase_client.py118
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/utils.py4
-rw-r--r--testapi/testapi-client/testapiclient/utils/clientmanager.py6
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
new file mode 100644
index 0000000..a624871
--- /dev/null
+++ b/testapi/docs/developer/devguide/images/CAS-sequence.jpg
Binary files differ
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:&nbsp;&nbsp;</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">&nbsp;{{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">&nbsp;{{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">&nbsp;{{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">&nbsp;{{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">&nbsp;{{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">&nbsp;{{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">&nbsp;{{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">&nbsp;{{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">&nbsp;{{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">&nbsp;{{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),