diff options
author | Edan Binshtok <eb578m@intl.att.com> | 2017-10-04 09:33:23 +0300 |
---|---|---|
committer | Edan Binshtok <eb578m@intl.att.com> | 2017-10-04 09:36:04 +0300 |
commit | f8907f0c4fc0ba4bb97a1d636a50c5b40c2642f2 (patch) | |
tree | 3d04d86910c93e42c055e5ed699ab1919482d5be /services | |
parent | 733e00df0a6fa19dd92ec7392966340345dd1885 (diff) |
Initial seed
Initial upload of django test framework
Change-Id: I643a7f4efc52cfafe4cc6d92e3178f36a0c1837c
Issue-Id: VVP-1
Signed-off-by: Edan Binshtok <eb578m@intl.att.com>
Diffstat (limited to 'services')
74 files changed, 9095 insertions, 0 deletions
diff --git a/services/__init__.py b/services/__init__.py new file mode 100644 index 0000000..30d7152 --- /dev/null +++ b/services/__init__.py @@ -0,0 +1,38 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. diff --git a/services/__pycache__/__init__.cpython-36.pyc b/services/__pycache__/__init__.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..aa1eba2 --- /dev/null +++ b/services/__pycache__/__init__.cpython-36.pyc diff --git a/services/__pycache__/constants.cpython-36.pyc b/services/__pycache__/constants.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..f2635de --- /dev/null +++ b/services/__pycache__/constants.cpython-36.pyc diff --git a/services/__pycache__/helper.cpython-36.pyc b/services/__pycache__/helper.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..60cf12a --- /dev/null +++ b/services/__pycache__/helper.cpython-36.pyc diff --git a/services/__pycache__/session.cpython-36.pyc b/services/__pycache__/session.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..eeb05fe --- /dev/null +++ b/services/__pycache__/session.cpython-36.pyc diff --git a/services/__pycache__/types.cpython-36.pyc b/services/__pycache__/types.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..b07c3cf --- /dev/null +++ b/services/__pycache__/types.cpython-36.pyc diff --git a/services/api/__init__.py b/services/api/__init__.py new file mode 100644 index 0000000..30d7152 --- /dev/null +++ b/services/api/__init__.py @@ -0,0 +1,38 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. diff --git a/services/api/__pycache__/__init__.cpython-36.pyc b/services/api/__pycache__/__init__.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..ece5c7a --- /dev/null +++ b/services/api/__pycache__/__init__.cpython-36.pyc diff --git a/services/api/__pycache__/api_bridge.cpython-36.pyc b/services/api/__pycache__/api_bridge.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..1da6617 --- /dev/null +++ b/services/api/__pycache__/api_bridge.cpython-36.pyc diff --git a/services/api/__pycache__/api_checklist.cpython-36.pyc b/services/api/__pycache__/api_checklist.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..6ea208f --- /dev/null +++ b/services/api/__pycache__/api_checklist.cpython-36.pyc diff --git a/services/api/__pycache__/api_gitlab.cpython-36.pyc b/services/api/__pycache__/api_gitlab.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..d4dedbc --- /dev/null +++ b/services/api/__pycache__/api_gitlab.cpython-36.pyc diff --git a/services/api/__pycache__/api_jenkins.cpython-36.pyc b/services/api/__pycache__/api_jenkins.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..905295c --- /dev/null +++ b/services/api/__pycache__/api_jenkins.cpython-36.pyc diff --git a/services/api/__pycache__/api_user.cpython-36.pyc b/services/api/__pycache__/api_user.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..1893ff4 --- /dev/null +++ b/services/api/__pycache__/api_user.cpython-36.pyc diff --git a/services/api/__pycache__/api_virtual_function.cpython-36.pyc b/services/api/__pycache__/api_virtual_function.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..35349c5 --- /dev/null +++ b/services/api/__pycache__/api_virtual_function.cpython-36.pyc diff --git a/services/api/api_bridge.py b/services/api/api_bridge.py new file mode 100644 index 0000000..8926a1d --- /dev/null +++ b/services/api/api_bridge.py @@ -0,0 +1,74 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +class APIBridge: + + """ + This class helps to use functions inside classes with circular import (dependencies). + Use this class only when there is circular import in one of the API services. + """ + + @staticmethod + def is_gitlab_ready(user_content): + """is_gitlab_ready: Originally can be found under APIGitLab class.""" + from services.api.api_gitlab import APIGitLab + return APIGitLab.is_gitlab_ready(user_content) + + @staticmethod + def login_user(email): + """login_user: Originally can be found under APIUser class.""" + from services.api.api_user import APIUser + return APIUser.login_user(email) + + @staticmethod + def set_ssh(user_content, sshKey): + """set_ssh: Originally can be found under APIUser class.""" + from services.api.api_user import APIUser + return APIUser.set_ssh(user_content, sshKey) + + @staticmethod + def create_engagement(wait_for_gitlab=True): + """create_engagement: Originally can be found under APIVirtualFunction class.""" + from services.api.api_virtual_function import APIVirtualFunction + return APIVirtualFunction.create_engagement(wait_for_gitlab) + + @staticmethod + def frontend_login(email, password): + """login: Originally can be found under FEUser class.""" + from services.frontend.fe_user import FEUser + return FEUser.login(email, password) diff --git a/services/api/api_checklist.py b/services/api/api_checklist.py new file mode 100644 index 0000000..ef7b8a3 --- /dev/null +++ b/services/api/api_checklist.py @@ -0,0 +1,219 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +import datetime +import logging + +import requests + +from services.api.api_gitlab import APIGitLab +from services.api.api_user import APIUser +from services.constants import Constants +from services.database.db_general import DBGeneral +from services.helper import Helper +from services.logging_service import LoggingServiceFactory + + +logger = LoggingServiceFactory.get_logger() + + +class APIChecklist: + + @staticmethod + def create_checklist(user_content, files=["file0", "file1"], return_negative_response=False): + r1 = None + postURL = Constants.Default.URL.Checklist.TEXT + \ + user_content['engagement_uuid'] + '/checklist/new/' + logger.debug("Post create checklist URL: " + postURL) + headers = dict() + headers['Content-type'] = 'application/json' + headers['Authorization'] = user_content['session_token'] + data = dict() + data['checkListAssociatedFiles'] = files + data['checkListName'] = "checklistAPI" + \ + Helper.rand_string('randomString') + data['checkListTemplateUuid'] = DBGeneral.select_where( + "uuid", "ice_checklist_template", "name", Constants.Template.Heat.TEXT, 1) + try: + if not APIGitLab.is_gitlab_ready(user_content): + raise Exception( + "Gitlab is not ready and because of that the test is failed.") + + r1 = requests.post(postURL, json=data, + headers=headers, verify=False) + + Helper.internal_assert_boolean(r1.status_code, 200) + logger.debug("Checklist was created successfully!") + cl_content = r1.json() + return cl_content + except: + if return_negative_response: + return r1 + if r1 is None: + logger.error( + "Failed to create checklist for VF " + user_content['vfName']) + else: + logger.error("Failed to create checklist for VF " + user_content[ + 'vfName'] + ", see response >>> %s %s.\nContent: %s" % (r1.status_code, r1.reason, str(r1.content, 'utf-8'))) + raise + + @staticmethod + def update_checklist(user_content, cl_uuid): + r1 = None + postURL = Constants.Default.URL.Checklist.Update.TEXT + '/' + cl_uuid + logger.debug("Post create checklist URL: " + postURL + '/' + cl_uuid) + headers = dict() # Create header for post request. + headers['Content-type'] = 'application/json' + headers['Authorization'] = user_content['session_token'] + data = dict() # Create JSON data for post request. + data['checklistUuid'] = cl_uuid + data['checkListAssociatedFiles'] = ["file1", "file2"] + data['checkListName'] = "UpdateChecklistAPI" + \ + Helper.rand_string('randomString') + data['checkListTemplateUuid'] = DBGeneral.select_where( + "uuid", "ice_checklist_template", "name", Constants.Template.Heat.TEXT, 1) + try: + r1 = requests.put( + postURL, json=data, headers=headers, verify=False) + Helper.internal_assert(r1.status_code, 200) + logger.debug("DBChecklist was created successfully!") + cl_content = r1.json() + return cl_content['uuid'] + except: + if r1 is None: + logger.error( + "Failed to create checklist for VF " + user_content['vfName']) + else: + logger.error("Failed to create checklist for VF " + user_content[ + 'vfName'] + ", see response >>> %s %s.\nContent: %s" % (r1.status_code, r1.reason, str(r1.content, 'utf-8'))) + raise + + @staticmethod + def add_checklist_audit_log(user_content, cl_uuid): + r1 = None + postURL = Constants.Default.URL.Checklist.Update + \ + cl_uuid + '/auditlog/' + logger.debug("Post checklist audit log URL: " + postURL) + headers = dict() # Create header for post request. + headers['Content-type'] = 'application/json' + headers['Authorization'] = user_content['session_token'] + data = dict() # Create JSON data for post request. + data['description'] = "API audit log test " + \ + Helper.rand_string('randomString') + try: + r1 = requests.post( + postURL, json=data, headers=headers, verify=False) + Helper.internal_assert_boolean(r1.status_code, 200) + logger.debug("Audit log was added successfully!") + except: + if r1 is None: + logger.error( + "Failed to add audit log for checklist uuid: " + cl_uuid) + else: + logger.error("Failed to add audit log for checklist uuid: " + cl_uuid + + ", see response >>> %s %s.\nContent: %s" % (r1.status_code, r1.reason, str(r1.content, 'utf-8'))) + raise + + @staticmethod + def add_checklist_next_step(user_content, cl_uuid): + r1 = None + postURL = Constants.Default.URL.Checklist.TEXT + \ + user_content['engagement_uuid'] + \ + '/checklist/' + cl_uuid + '/nextstep/' + logger.debug("Post checklist next step URL: " + postURL) + headers = dict() # Create header for post request. + headers['Content-type'] = 'application/json' + headers['Authorization'] = user_content['session_token'] + data = dict() # Create JSON data for post request. + data['files'] = ["file0"] + data['assigneesUuids'] = [user_content['uuid']] + data['duedate'] = str(datetime.date.today()) + data['description'] = "API next step test " + \ + Helper.rand_string('randomString') + list_data = [] + list_data.append(data) + try: + r1 = requests.post( + postURL, json=list_data, headers=headers, verify=False) + Helper.internal_assert(r1.status_code, 200) + logger.debug("Next step was added successfully!") + ns_uuid = r1.json() + return ns_uuid[0]['uuid'] + except: + if r1 is None: + logger.error( + "Failed to add next step for checklist uuid: " + cl_uuid) + else: + logger.error("Failed to add next step for checklist uuid: " + cl_uuid + + ", see response >>> %s %s.\nContent: %s" % (r1.status_code, r1.reason, str(r1.content, 'utf-8'))) + raise + + @staticmethod + def jump_state(checklistUUID, engLeadEmail): + token = APIUser.login_user(engLeadEmail) + stateURL = Constants.Default.URL.Checklist.Rest.TEXT + \ + str(checklistUUID) + '/state/' + APIChecklist.go_to_next_state(stateURL, token) + + @staticmethod + def go_to_next_state(url, token): + headers = {"Authorization": "token " + token} + body = dict() + body['description'] = "" + body['decline'] = "False" + r = requests.put(url, headers=headers, json=body, verify=False) + if (r.status_code == 201 or r.status_code == 200): + logger.debug("go_to_next_state put request result status: %s" % + r.status_code) + else: + logger.error( + "PUT request failed to change checklist state >>> " + str(r.status_code) + " " + r.reason) + raise Exception("PUT request failed to change checklist state") + + @staticmethod + def move_cl_to_closed(cl_uuid, vf_staff_emails): + api_checklist_obj = APIChecklist() + + for i in range(len(vf_staff_emails)): + logger.debug("Trying to jump state for %s [%s]" % (vf_staff_emails[i], i)) + api_checklist_obj.jump_state(cl_uuid, vf_staff_emails[i]) + + # Move CL to closed state. + logger.debug("Trying to jump state 'closed' for %s" % vf_staff_emails[0]) + api_checklist_obj.jump_state(cl_uuid, vf_staff_emails[0]) + diff --git a/services/api/api_gitlab.py b/services/api/api_gitlab.py new file mode 100644 index 0000000..c7b25e0 --- /dev/null +++ b/services/api/api_gitlab.py @@ -0,0 +1,394 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +import logging +import os +import subprocess +import sys +import time + +from django.conf import settings +import git +import requests + +from services.api.api_bridge import APIBridge +from services.constants import Constants +from services.database.db_virtual_function import DBVirtualFunction +from services.helper import Helper +from services.logging_service import LoggingServiceFactory +from services.session import session + + +logger = LoggingServiceFactory.get_logger() + +class APIGitLab: + + @staticmethod + def display_output(p): + while True: + out = p.stderr.read(1) + if out == b'' and p.poll() != None: + break + if out != '': + sys.stdout.write(str(out.decode())) + sys.stdout.flush() + + @staticmethod + def get_git_project(path_with_namespace): + r1 = None + getURL = Constants.Default.URL.GitLab.Projects.TEXT + \ + path_with_namespace + logger.debug("Get project URL: " + getURL) + headers = dict() # Create header for post request. + headers['Content-type'] = 'application/json' + headers['PRIVATE-TOKEN'] = settings.GITLAB_TOKEN + try: + r1 = requests.get(getURL, headers=headers, verify=False) + Helper.internal_assert(r1.status_code, 200) + counter = 0 + while r1.content == b'[]' and counter <= Constants.GitLabConstants.RETRIES_NUMBER: + time.sleep(session.wait_until_time_pause) + r1 = requests.get(getURL, headers=headers, verify=False) + Helper.internal_assert(r1.status_code, 200) + + if r1.content == b'[]': + logger.error("Got an empty list as a response.") + raise + logger.debug("Project exists on APIGitLab!") + content = r1.json() # Change it from list to dict. + return content + except: + if r1 is None: + logger.error("Failed to get project from APIGitLab.") + else: + logger.error("Failed to get project from APIGitLab, see response >>> %s %s \n %s" + % (r1.status_code, r1.reason, str(r1.content, 'utf-8'))) + raise + + def are_all_list_users_registered_as_project_members(self, users_emails_list, project_path_with_namespace): + for email in users_emails_list: + if not self.validate_git_project_members(project_path_with_namespace, email): + raise Exception( + "Couldn't find the invited users: " + email + " in GitLab.") + logger.debug( + "Invited user: " + email + " found in GitLab.") + + @staticmethod + def validate_git_project_members(path_with_namespace, user_email): + if settings.DATABASE_TYPE != 'local': + r1 = None + headers = dict() + git_user = APIGitLab.get_git_user(user_email) + getURL = Constants.Default.URL.GitLab.Projects.TEXT + \ + path_with_namespace + "/members/" + str(git_user['id']) + logger.debug("Get project members URL: " + getURL) + headers['Content-type'] = 'application/json' + headers['PRIVATE-TOKEN'] = settings.GITLAB_TOKEN + counter = 0 + while (r1 is None or r1.content == b'[]' or r1.status_code != 200) and counter <= Constants.GitLabConstants.RETRIES_NUMBER: + logger.debug( + "try to get git project members (try #%s)" % counter) + time.sleep(session.wait_until_time_pause) + try: + r1 = requests.get(getURL, headers=headers, verify=False) + counter += 1 + except Exception as e: + if counter >= Constants.GitLabConstants.RETRIES_NUMBER: + logger.error("Failed to get project's team members from APIGitLab, see response >>> %s %s \n %s %s" + % (r1.status_code, r1.reason, str(r1.content, 'utf-8'), e.message)) + return False + if r1.content == b'[]': + logger.error("Got an empty list as a response.") + return False + elif r1.status_code != 200: + logger.error("Got %s %s." % (r1.status_code, r1.reason)) + return False + logger.debug("Got %s %s, user found in project." % + (r1.status_code, r1.reason)) + return True + + @staticmethod + def negative_validate_git_project_member(path_with_namespace, user_email, git_user_id): + if settings.DATABASE_TYPE != 'local': + r1 = None + headers = dict() + getURL = Constants.Default.URL.GitLab.Projects.TEXT + \ + path_with_namespace + "/members/" + git_user_id + logger.debug("Get project members URL: " + getURL) + headers['Content-type'] = 'application/json' + headers['PRIVATE-TOKEN'] = settings.GITLAB_TOKEN + counter = 0 + while r1 is None or str.encode(user_email) not in r1.content and counter <= Constants.GitLabConstants.RETRIES_NUMBER: + logger.debug( + "try to get git project members (try #%s)" % counter) + time.sleep(session.wait_until_time_pause) + try: + r1 = requests.get(getURL, headers=headers, verify=False) + counter += 1 + except Exception as e: + if counter >= Constants.GitLabConstants.RETRIES_NUMBER: + logger.error("Failed to get project's team members from APIGitLab, see response >>> %s %s \n %s %s" + % (r1.status_code, r1.reason, str(r1.content, 'utf-8'), e.message)) + return False + + if r1.content == b'[]': + logger.debug("Got %s %s, user not found in project." % + (r1.status_code, r1.reason)) + return True + else: + logger.debug("Got %s %s, user found in project." % + (r1.status_code, r1.reason)) + return False + + @staticmethod + def get_git_user(user_email): + if settings.DATABASE_TYPE != 'local': + r1 = None + user_email = user_email.replace("@", "_at_") + getURL = settings.GITLAB_URL + \ + "api/v3/users?username=" + user_email + logger.debug("Get user URL: " + getURL) + headers = dict() # Create header for post request. + headers['Content-type'] = 'application/json' + headers['PRIVATE-TOKEN'] = settings.GITLAB_TOKEN + try: + r1 = requests.get(getURL, headers=headers, verify=False) + Helper.internal_assert(r1.status_code, 200) + counter = 0 + while r1.content == b'[]' and counter <= 60: + logger.info( + "Will try to get gitlab user until will be response... #%s" % counter) + time.sleep(session.wait_until_time_pause_long) + r1 = requests.get(getURL, headers=headers, verify=False) + Helper.internal_assert(r1.status_code, 200) + counter += 1 + + if r1.content == b'[]': + logger.error("Got an empty user from gitlab.") + raise Exception("Got an empty user from gitlab.") + + logger.debug("Got %s %s and received user data: %s." % + (r1.status_code, r1.reason, r1.content)) + content = r1.json() + return content[0] + except: + if r1 is None: + logger.error("Failed to get user from APIGitLab.") + else: + logger.error("Failed to get user from APIGitLab, see response >>> %s %s \n %s" + % (r1.status_code, r1.reason, str(r1.content, 'utf-8'))) + raise + + @staticmethod + def get_git_user_ssh_key(git_user_id): + r1 = None + getURL = Constants.Default.URL.GitLab.Users.TEXT + \ + str(git_user_id) + "/keys" + logger.debug("Get user URL: " + getURL) + headers = dict() # Create header for post request. + headers['Content-type'] = 'application/json' + headers['PRIVATE-TOKEN'] = settings.GITLAB_TOKEN + try: + r1 = requests.get(getURL, headers=headers, verify=False) + Helper.internal_assert(r1.status_code, 200) + if r1.content == '[]': + logger.error("Got an empty list as a response.") + raise + logger.debug("Got %s %s and received user's public key." % + (r1.status_code, r1.reason)) + content = r1.json() # Change it from list to dict. + gitPubKey = content[0]['key'] + return gitPubKey + except: + if r1 is None: + logger.error("Failed to get user's public key from APIGitLab.") + else: + logger.error("Failed to get user's public key from APIGitLab, see response >>> %s %s \n %s" + % (r1.status_code, r1.reason, str(r1.content, 'utf-8'))) + raise + + @staticmethod + def git_clone_push(user_content): + if settings.DATABASE_TYPE != 'local': + logger.debug( + "About to push files into project's repository on the local folder(not over origin).") + try: + user_content['session_token'] = "token " + \ + APIBridge.login_user(Constants.Users.Admin.EMAIL) + used_email_for_actions = Constants.Users.Admin.EMAIL + repo_dir = Constants.Paths.LocalGitFolder.PATH + \ + user_content['vfName'] + if not os.path.exists(repo_dir): + os.makedirs(repo_dir) + logger.debug("Created the following folder: %s" % repo_dir) + # Create pair of keys for user. + user_pub_key = Helper.get_or_create_rsa_key_for_admin() + DBVirtualFunction.add_admin_to_eng_team( + user_content['engagement_uuid']) + # Set SSH Key for the user. + APIBridge.set_ssh(user_content, user_pub_key) + git_user = APIGitLab.get_git_user(used_email_for_actions) + + counter = 0 + git_user_pub_key = None + while user_pub_key != git_user_pub_key and counter < Constants.GitLabConstants.RETRIES_NUMBER: + try: + git_user_pub_key = APIGitLab.get_git_user_ssh_key( + git_user['id']) + except Exception as e: + pass + + counter += 1 + time.sleep(session.wait_until_time_pause) + + # Check that the SSH key was added to user on APIGitLab. + if user_pub_key != git_user_pub_key: + raise Exception("The SSH Key received does not equal to the" + " one provided! The key from" + "APIGitLab:\n %s ==<>== %s" + % (git_user_pub_key, user_pub_key)) + + gitRepoURL = "git@gitlab:%s/%s.git" % ( + user_content['engagement_manual_id'], user_content['vfName']) + logger.debug("Clone repo from: " + gitRepoURL) + APIGitLab.is_gitlab_ready(user_content) + cmd = 'cd ' + repo_dir + \ + '; git config --global user.email \"' + Constants.Users.Admin.EMAIL + \ + '\"; git config --global user.name \"' + \ + Constants.Users.Admin.FULLNAME + '\";' + # Commit all changes. + p = subprocess_popen = subprocess.Popen( + cmd, shell=True, stderr=subprocess.PIPE) + while subprocess_popen is None: + logger.debug( + "waiting to subprocess command to complete...") + APIGitLab.display_output(p) + # Clone project from APIGitLab. + repo = git.Repo.clone_from(gitRepoURL, repo_dir) + logger.debug("Successfully cloned repo to " + repo_dir) + # Create three files (file0, file1, file2) and add them to git + # index. + for i in range(3): + fileName = repo_dir + '/file' + str(i) + with open(fileName, 'w') as content_file: + os.chmod(fileName, 0o600) + content_file.write("Test file " + fileName) + repo.index.add([fileName]) + logger.debug( + fileName + " was created and added to commit list.") + cmd = 'cd ' + repo_dir + \ + '; git commit -a -m \"Create and add 3 files to git.\"' + # Commit all changes. + p = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE) + APIGitLab.display_output(p) + logger.debug("All files added to commit list.") + cmd = 'cd ' + repo_dir + '; git push' + # Push commit to APIGitLab. + p = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE) + APIGitLab.display_output(p) + logger.debug("All files were pushed to APIGitLab.") + except Exception as e: + logger.error( + "_-_-_-_-_- Unexpected error in git_clone_push: " + str(e)) + raise Exception(e) + + @staticmethod + def git_push_commit(user_content): + if settings.DATABASE_TYPE != 'local': + logger.debug( + "About to push files into project's repository on APIGitLab") + try: + git_work = '/tmp/git_work/' + repo_dir = git_work + user_content['vfName'] + # Create three files (file0, file1, file2) and add them to git + # index. + for i in range(3): + fileName = repo_dir + '/file' + str(i) + with open(fileName, 'w') as content_file: + os.chmod(fileName, 0o600) + content_file.write("Edit test file " + fileName) + logger.debug(fileName + " was edited.") + cmd = 'cd ' + repo_dir + \ + '; git commit -a -m \"Create and add 3 files to git.\"' + # Commit all changes. + p = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE) + APIGitLab.display_output(p) + logger.debug("All edited files were committed.") + cmd = 'cd ' + repo_dir + '; git push' + # Push commit to APIGitLab. + p = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE) + APIGitLab.display_output(p) + logger.debug( + "All edited files were commited and pushed to APIGitLab.") + except Exception as e: + logger.error( + "_-_-_-_-_- Unexpected error in git_push_commit : " + str(e)) + raise Exception( + "Something went wrong on git_push_commit function, please check logs.") + + @staticmethod + def is_gitlab_ready(user_content): + counter = 1 + gettURL = settings.ICE_EM_URL + '/v1/engmgr/engagement/' + \ + user_content['engagement_uuid'] + '/checklist/new/' + logger.debug( + "Get URL to check if GitLab and Jenkins are ready: " + gettURL) + # Validate with EL + token = "token " + APIBridge.login_user(user_content['el_email']) + headers = dict() # Create header for get request. + headers['Content-type'] = 'application/json' + headers['Authorization'] = token + r1 = requests.get(gettURL, headers=headers, verify=False) + while (r1.content == b'"Create New checklist is not ready yet"' and counter <= + Constants.GitLabConstants.RETRIES_NUMBER): + time.sleep(session.wait_until_time_pause_long) + logger.debug( + "GitLab and Jenkins are not ready yet, trying again (%s of %s)" % + (counter, Constants.GitLabConstants.RETRIES_NUMBER)) + r1 = requests.get(gettURL, headers=headers, verify=False) + counter += 1 + if r1.status_code != 200: + if r1.content == "Create New checklist is not ready yet": + raise Exception("Max retries exceeded, failing test...") + else: + raise Exception("Something went wrong while waiting for GitLab and Jenkins. %s %s" % ( + r1.status_code, r1.reason)) + return False + elif r1.status_code == 200: + logger.debug("Gitlab and Jenkins are ready to continue!") + return True diff --git a/services/api/api_jenkins.py b/services/api/api_jenkins.py new file mode 100644 index 0000000..e1e1f6e --- /dev/null +++ b/services/api/api_jenkins.py @@ -0,0 +1,81 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +from django.conf import settings +import requests +from requests.auth import HTTPBasicAuth + +from services.constants import Constants +from services.helper import Helper +from services.logging_service import LoggingServiceFactory + + +logger = LoggingServiceFactory.get_logger() + +class APIJenkins: + + @staticmethod + def get_jenkins_job(job_name): + r1 = None + getURL = settings.JENKINS_URL + "job/" + job_name + logger.debug("Get APIJenkins job URL: " + getURL) + try: + r1 = requests.get(getURL, auth=HTTPBasicAuth( + settings.JENKINS_USERNAME, settings.JENKINS_PASSWORD)) + Helper.internal_assert(r1.status_code, 200) + logger.debug("Job was created on APIJenkins!") + except: + msg = None + + if r1 is None: + msg = "APIJenkins didn't create job for %s" % job_name + else: + msg = "APIJenkins didn't create job for %s, see response >>> %s %s" % ( + job_name, r1.status_code, r1.reason) + + logger.error(msg) + raise Exception(msg) + + @staticmethod + def find_build_num_out_of_jenkins_log(log): + lines_array = log.splitlines() + for line in lines_array: + if Constants.Dashboard.Checklist.JenkinsLog.Modal.Body.BUILD_IDENTIFIER in line: + parts = line.partition('jenkins') + return parts[2] + diff --git a/services/api/api_rados.py b/services/api/api_rados.py new file mode 100644 index 0000000..61cfa5c --- /dev/null +++ b/services/api/api_rados.py @@ -0,0 +1,161 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +import logging +import time + +from boto.s3.connection import S3Connection, OrdinaryCallingFormat +from django.conf import settings + +from rados.rgwa_client_factory import RGWAClientFactory +from services.constants import Constants +from services.logging_service import LoggingServiceFactory +from services.session import session + + +logger = LoggingServiceFactory.get_logger() + +class APIRados: + + @staticmethod + def get_bucket(name): + """Return the Bucket.""" + boto_conn = RGWAClientFactory.standard() + try: + return boto_conn.lookup(name) + except Exception as e: + logger.error("Problem on get bucket", e) + raise e + + @staticmethod + def get_bucketfor_specific_user(name, access_key_id, secret_access_key): + """Return the Bucket.""" + boto_conn = APIRados.specific_client(access_key_id, secret_access_key) + try: + return boto_conn.lookup(name) + except Exception as e: + logger.error("Problem on get bucket for specific user", e) + raise e + + @staticmethod + def get_bucket_grants(bucket_name): + """Return the Grants.""" + counter = 1 + bucket = APIRados.get_bucket(bucket_name) + while not bucket and counter <= Constants.RGWAConstants.BUCKET_RETRIES_NUMBER: + logger.error("Bucket not found. Retry #%s" % counter) + time.sleep(session.wait_until_time_pause_long) + bucket = APIRados.get_bucket(bucket_name) + counter += 1 + if not bucket: + raise TimeoutError("Max retries exceeded, failing test...") + grants = bucket.list_grants() + print("***********grants=", grants) + return grants + + @staticmethod + def is_bucket_ready(bucket_id): + counter = 1 + bucket = APIRados.get_bucket(bucket_id) + while (bucket == None and counter <= + Constants.RGWAConstants.BUCKET_RETRIES_NUMBER): + time.sleep(session.wait_until_time_pause_long) + logger.debug( + "bucket are not ready yet, trying again (%s of 180)" % counter) + bucket = APIRados.get_bucket(bucket_id) + counter += 1 + print("****_+__+bucket= ", str(bucket)) + time.sleep(session.wait_until_time_pause_long) + if bucket == None: + raise TimeoutError("Max retries exceeded, failing test...") + elif bucket != None: + logger.debug("bucket are ready to continue!") + return True + + @staticmethod + def users_of_bucket_ready_after_complete(bucket_id, user_name): + grants = APIRados.get_bucket_grants(bucket_id) + count = 0 + counter = 1 + while (count != 0 and counter <= + Constants.RGWAConstants.BUCKET_RETRIES_NUMBER): + grants = APIRados.get_bucket_grants(bucket_id) + time.sleep(session.wait_until_time_pause_long) + for g in grants: + if g.id == user_name: + count = +1 + time.sleep(session.wait_until_time_pause_long) + if count != 0: + raise Exception("Max retries exceeded, failing test...") + return False + elif count == 0: + logger.debug("users_of_bucket are ready to continue!") + return True + + @staticmethod + def users_of_bucket_ready_after_created(bucket_id, user_name): + grants = APIRados.get_bucket_grants(bucket_id) + count = 0 + counter = 1 + while (count == 0 and counter <= + Constants.RGWAConstants.BUCKET_RETRIES_NUMBER): + grants = APIRados.get_bucket_grants(bucket_id) + time.sleep(session.wait_until_time_pause_long) + for g in grants: + if g.id == user_name: + count = +1 + time.sleep(session.wait_until_time_pause_long) + if count == 0: + raise Exception("Max retries exceeded, failing test...") + return False + elif count > 0: + logger.debug("users_of_bucket are ready to continue!") + return True + + @staticmethod + def specific_client(access_key_id, secret_access_key): + boto_conn = S3Connection( + host=settings.AWS_S3_HOST, + port=settings.AWS_S3_PORT, + aws_access_key_id=access_key_id, + aws_secret_access_key=secret_access_key, + calling_format=OrdinaryCallingFormat(), + is_secure=True,) + + boto_conn.num_retries = 0 + return boto_conn diff --git a/services/api/api_user.py b/services/api/api_user.py new file mode 100644 index 0000000..3e38fd2 --- /dev/null +++ b/services/api/api_user.py @@ -0,0 +1,308 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +import re + +from django.conf import settings +import requests + +from services.api.api_bridge import APIBridge +from services.api.api_gitlab import APIGitLab +from services.constants import Constants, ServiceProvider +from services.helper import Helper +from services.logging_service import LoggingServiceFactory + + +logger = LoggingServiceFactory.get_logger() + +class APIUser: + + @staticmethod + # Update account API - only adds new SSH key! + def update_account(user_content): + r1 = None + token = APIUser.login_user(user_content['email']) + user_content['session_token'] = 'token ' + token + sshKey = Helper.generate_sshpub_key() + putURL = settings.ICE_EM_URL + '/v1/engmgr/users/account' + logger.debug("Put user URL: " + putURL) + headers = dict() # Create header for put request. + headers['Content-type'] = 'application/json' + headers['Authorization'] = user_content['session_token'] + # headers['Authorization'] = user_content['activation_token'] + put_data = dict() # Create JSON data for put request. + user_content['vendor'] = user_content['company']['name'] + if user_content['vendor'] == "AT&T": + put_data['company'] = "AT&T" + else: + put_data['company'] = user_content['vendor'] + put_data['email'] = user_content['email'] + put_data['full_name'] = user_content['full_name'] + put_data['password'] = "" + put_data['phone_number'] = "+1201" + \ + Helper.rand_string("randomNumber", 6) + put_data['ssh_key'] = sshKey + try: + r1 = requests.put( + putURL, json=put_data, headers=headers, verify=False) + Helper.internal_assert(r1.status_code, 200) + logger.debug( + "SSH Key was added successfully to user " + user_content['full_name']) + if not APIBridge.is_gitlab_ready(user_content): + raise + return sshKey + except: + if r1 is None: + logger.error("Failed to add public SSH key to user.") + else: + logger.error("PUT request failed to add SSH key to user, see response >>> %s %s \n %s" % ( + r1.status_code, r1.reason, str(r1.content, 'utf-8'))) + raise + + @staticmethod + # Update account API - only adds new SSH key! + def update_account_injec_script(user_content): + r1 = None + putURL = settings.ICE_EM_URL + '/v1/engmgr/users/account' + logger.debug("Put user URL: " + putURL) + headers = dict() # Create header for put request. + headers['Content-type'] = 'application/json' + headers['Authorization'] = user_content['session_token'] + put_data = dict() # Create JSON data for put request. + if user_content['vendor'] == "AT&T": + put_data['company'] = "AT&T" + else: + put_data['company'] = user_content['vendor'] + put_data['email'] = user_content['email'] + script = "<script>;</script>" + put_data['full_name'] = script + put_data['password'] = "" + put_data['phone_number'] = "+1201" + \ + Helper.rand_string("randomNumber", 6) + try: + r1 = requests.put( + putURL, json=put_data, headers=headers, verify=False) + Helper.internal_assert(r1.status_code, 200) + msg = "Testing for Cross site scripting successfully : " + \ + user_content['full_name'] + \ + "stattus Code = " + str(r1.status_code) + logger.debug(msg) + if not APIBridge.is_gitlab_ready(user_content): + raise + return True + except: + if r1 is None: + logger.error("Failed to add public SSH key to user.") + else: + logger.error("PUT request failed to add SSH key to user, see response >>> %s %s \n %s" % ( + r1.status_code, r1.reason, str(r1.content, 'utf-8'))) + raise + + @staticmethod + def create_new_user(company=False, activate=False): + signupUrl = settings.EM_REST_URL + "signup/" + signupParams = APIUser.create_signup_param(company) + r1 = requests.post(signupUrl, json=signupParams, verify=False) + if (r1.status_code == 201 or r1.status_code == 200): + logger.debug("Moving to next test case. status=" + + str(r1.status_code)) + pass # Need to break here. + try: + user_data = r1.json() + except Exception as e: + logger.error("=========== json error ========") + logger.error("r1.content = " + str(r1.content) + + ", status=" + str(r1.status_code)) + logger.error("=========== json error end ========") + raise e + if activate: + APIUser.activate_user( + user_data['uuid'], user_data["user"]["activation_token"]) + return user_data + + @staticmethod + def login_user(email): + postUrl = settings.EM_REST_URL + "login" + user_data = dict() # Create JSON data for post request. + user_data['email'] = email + user_data['password'] = "iceusers" + try: + headers = {'Content-type': 'application/json'} + r = requests.post( + postUrl, json=user_data, headers=headers, verify=False) + logger.debug(str(r.status_code) + " " + r.reason) + decoded_response = r.json() + return decoded_response['token'] + except: + logger.debug("Failed to login.") + raise + + @staticmethod + def set_ssh(user_content, sshKey=None): # Set SSH key to user. + r1 = None + if sshKey is None: + logger.debug("About to generate an ssh key for the user: %s" % + user_content['email']) + sshKey = Helper.generate_sshpub_key() + postURL = settings.ICE_EM_URL + '/v1/engmgr/users/ssh' + logger.debug("Post user URL: " + postURL) + headers = dict() # Create header for post request. + headers['Content-type'] = 'application/json' + headers['Authorization'] = user_content['session_token'] + post_data = dict() # Create JSON data for post request. + post_data['ssh_key'] = sshKey + try: + r1 = requests.post( + postURL, json=post_data, headers=headers, verify=False) + Helper.internal_assert(r1.status_code, 200) + logger.debug( + "SSH Key was added successfully") + if not APIBridge.is_gitlab_ready(user_content): + raise + return sshKey + except: + if r1 is None: + logger.error("Failed to add public SSH key.") + else: + logger.error( + "POST request failed to add SSH key to user, see response >>> %s %s" % (r1.status_code, r1.reason)) + raise + + @staticmethod + def create_signup_param(company=False): + try: # Click on element in UI, by xPath locator. + if not company: + company = ServiceProvider.MainServiceProvider + email_domain = ServiceProvider.email + else: + email_domain = company.lower() + ".com" # + data = { + "company": company, + "full_name": Helper.rand_string("randomString"), + "email": Helper.rand_string("randomString") + "@" + email_domain, + "phone_number": Constants.Default.Phone.TEXT, + "password": Constants.Default.Password.TEXT, + "regular_email_updates": "True" + } + + return data + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "Could not create Sign Up parametrs" + raise Exception(errorMsg, e) + + @staticmethod + def activate_user(userUuid, activationToken): + postUrl = settings.ICE_EM_URL + "/v1/engmgr/users/activate/" + \ + userUuid + "/" + activationToken + logger.debug(postUrl) + r1 = requests.get(postUrl, verify=False) + if (r1.status_code == 200): + logger.debug("APIUser activated successfully!") + return True + else: + raise Exception( + "Failed to activate user >>> %s %s" % (r1.status_code, r1.reason)) + + @staticmethod + def signup_invited_user(company, invited_email, invite_token, invite_url, user_content, is_contact_user="false", activate=False, wait_for_gitlab=True): + r1 = None + postURL = settings.ICE_EM_URL + '/v1/engmgr/signup' + logger.debug("Post signup URL: " + postURL) + if is_contact_user == "true": + fullName = re.sub("http.*full_name=", "", invite_url) + fullName = re.sub("&.*", "", fullName) + logger.debug( + "Invited contact full name is (according to url): " + fullName) + else: + fullName = Helper.rand_string('randomString') + + post_data = dict() # Create JSON data for post request. + post_data['company'] = company + post_data['email'] = invited_email + post_data['full_name'] = fullName + post_data['invitation'] = invite_token + post_data['is_contact_user'] = is_contact_user + post_data['password'] = "iceusers" + post_data['phone_number'] = "+1201" + \ + Helper.rand_string("randomNumber", 6) + post_data['regular_email_updates'] = "False" + post_data['terms'] = "True" + try: + requests.get(invite_url, verify=False) + r1 = requests.post( + postURL, json=post_data, verify=False) + Helper.internal_assert(r1.status_code, 200) + logger.debug("Invited user signed-up successfully!") + + user_data = r1.json() + if activate: + APIUser.activate_user( + user_data['uuid'], user_data["user"]["activation_token"]) + + if wait_for_gitlab: + if not APIBridge.is_gitlab_ready(user_content): + raise + return post_data + except: + if r1 is None: + logger.error("Failed to sign up the invited team member.") + else: + logger.error("POST request failed to sign up the invited team member, see response >>> %s %s \n %s" % ( + r1.status_code, r1.reason, str(r1.content, 'utf-8'))) + raise + + @staticmethod + def create_new_user_content(): + user_content = APIBridge.create_engagement() + APIGitLab.git_clone_push(user_content) + APIBridge.frontend_login( + user_content['email'], Constants.Default.Password.TEXT) + vfName = user_content['vfName'] + uuid = user_content['uuid'] + inviteEmail = Helper.rand_invite_email() + newObj = [vfName, uuid, inviteEmail] + return newObj, user_content + + @staticmethod + def create_new_user_content_login_with_api(): + user_content = APIBridge.create_engagement() + APIGitLab.git_clone_push(user_content) + token = "token " + APIBridge.login_user(user_content['el_email']) + user_content['session_token'] = token + return user_content diff --git a/services/api/api_virtual_function.py b/services/api/api_virtual_function.py new file mode 100644 index 0000000..46610e8 --- /dev/null +++ b/services/api/api_virtual_function.py @@ -0,0 +1,368 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +import datetime +import json +import time + +from django.conf import settings +import requests + +from services.api.api_gitlab import APIGitLab +from services.api.api_user import APIUser +from services.constants import Constants, ServiceProvider +from services.database.db_general import DBGeneral +from services.helper import Helper +from services.logging_service import LoggingServiceFactory + + +logger = LoggingServiceFactory.get_logger() + + +class APIVirtualFunction: + + @staticmethod + def add_next_step(user_content, files=[]): + r1 = None + postURL = settings.ICE_EM_URL + '/v1/engmgr/engagements/' + \ + user_content['engagement_uuid'] + '/nextsteps' + logger.debug("Post add next step URL: " + postURL) + headers = dict() # Create header for post request. + headers['Content-type'] = 'application/json' + headers['Authorization'] = user_content['session_token'] + data = dict() # Create JSON data for post request. + files_list = list() + if type(files) is list: + for file in files: + files_list.append(file) + else: + files_list.append(files) + data['files'] = files_list + data['assigneesUuids'] = [user_content['uuid']] + data['duedate'] = str(datetime.date.today()) + data['description'] = "API test - add next step." + list_data = [] + list_data.append(data) + try: + r1 = requests.post( + postURL, json=list_data, headers=headers, verify=False) + Helper.internal_assert(r1.status_code, 200) + logger.debug("Next step was added to the engagement!") + ns_uuid = r1.json() + return ns_uuid[0]['uuid'] + except: + if r1 is None: + logger.error( + "Failed to add next step to VF " + user_content['vfName']) + else: + logger.error("Failed to add next step to VF " + user_content[ + 'vfName'] + ", see response >>> %s %s.\nContent: %s" % (r1.status_code, r1.reason, str(r1.content, 'utf-8'))) + raise + + @staticmethod + def create_vf(token): + r1 = None + postUrl = settings.EM_REST_URL + "vf/" + targetVersion = DBGeneral.select_from( + "uuid", "ice_deployment_target", 1) + ecompRelease = DBGeneral.select_from("uuid", "ice_ecomp_release", 1) + headers = dict() # Create header for post request. + headers['Content-type'] = 'application/json' + headers['Authorization'] = 'token ' + token + jdata = [{"virtual_function": Helper.rand_string("randomString"), + "version": Helper.rand_string("randomString") + Helper.rand_string("randomNumber"), + "target_lab_entry_date": time.strftime("%Y-%m-%d"), + "target_aic_uuid": targetVersion, + "ecomp_release": ecompRelease, + "is_service_provider_internal": False}] + try: + r1 = requests.post( + postUrl, json=jdata, headers=headers, verify=False) + Helper.internal_assert(r1.status_code, 200) + logger.debug("Virtual Function created successfully!") + content = r1.content[1:-1] + return content + except: + if r1 is None: + logger.debug("Failed to create VF >>> request failed!") + else: + logger.debug( + "Failed to create VF >>> %s %s \n %s" % (r1.status_code, r1.reason, str(r1.content, 'utf-8'))) + raise + + @staticmethod + def get_engagement(user_content): + r1 = None + postUrl = settings.EM_REST_URL + 'single-engagement/' + \ + str(user_content['engagement_uuid'],) + headers = dict() # Create header for post request. + headers['Content-type'] = 'application/json' + headers['Authorization'] = user_content['session_token'] + try: + r1 = requests.get( + postUrl, headers=headers, verify=False) + Helper.internal_assert(r1.status_code, 200) + logger.debug("Retrieved the Engagement successfully!") + content = r1.content + return json.loads(content) + except: + if r1 is None: + logger.debug( + "Failed to Retrieve the Engagement >>> request failed!") + else: + logger.debug( + "Failed to Retrieve the Engagement >>> %s %s \n %s" % (r1.status_code, r1.reason, str(r1.content, 'utf-8'))) + raise + + @staticmethod + def invite_team_member(user_content): + r1 = None + postURL = settings.ICE_EM_URL + '/v1/engmgr/invite-team-members/' + logger.debug("Post invite user URL: " + postURL) + headers = dict() # Create header for post request. + headers['Content-type'] = 'application/json' + headers['Authorization'] = user_content['session_token'] + data = dict() # Create JSON data for post request. + data['email'] = Helper.rand_string( + 'randomString') + "@" + ServiceProvider.email + data['eng_uuid'] = user_content['engagement_uuid'] + list_data = [] + list_data.append(data) + try: + r1 = requests.post( + postURL, json=list_data, headers=headers, verify=False) + Helper.internal_assert_boolean(r1.status_code, 200) + logger.debug("Invite sent successfully to email " + data['email']) + invite_token = DBGeneral.select_where_and("invitation_token", "ice_invitation", "email", data[ + 'email'], "engagement_uuid", user_content['engagement_uuid'], 1) + invite_url = settings.ICE_PORTAL_URL + "/#/signUp?invitation=" + invite_token + \ + "&email=" + data['email'] + logger.debug("Invitation URL is: " + invite_url) + return data['email'], invite_token, invite_url + except: + if r1 is None: + logger.error("Failed to invite team member.") + else: + logger.error( + "POST request failed to invite team member, see response >>> %s %s" % (r1.status_code, r1.reason)) + raise + + @staticmethod + def add_contact(user_content): + r1 = None + postURL = settings.ICE_EM_URL + '/v1/engmgr/add-contact/' + logger.debug("Post invite vendor contact URL: " + postURL) + headers = dict() # Create header for post request. + headers['Content-type'] = 'application/json' + headers['Authorization'] = user_content['session_token'] + data = dict() # Create JSON data for post request. + data['company'] = user_content['vendor_uuid'] + data['email'] = Helper.rand_string( + 'randomString') + "@" + ServiceProvider.email + data['eng_uuid'] = user_content['engagement_uuid'] + data['full_name'] = Helper.rand_string('randomString') + data['phone_number'] = "+1201" + Helper.rand_string("randomNumber", 6) + try: + r1 = requests.post( + postURL, json=data, headers=headers, verify=False) + Helper.internal_assert_boolean(r1.status_code, 200) + logger.debug("Invite sent successfully to email " + data['email']) + invite_token = DBGeneral.select_where_and("invitation_token", "ice_invitation", "email", data[ + 'email'], "engagement_uuid", user_content['engagement_uuid'], 1) + invite_url = settings.ICE_PORTAL_URL + "/#/signUp?invitation=" + invite_token + \ + "&email=" + data['email'] + "&full_name=" + data['full_name'] + \ + "&phone_number=" + \ + data['phone_number'] + "&company=" + \ + data['company'] + "&is_contact_user=true" + logger.debug("Invitation URL is: " + invite_url) + return data['email'], invite_token, invite_url + except: + if r1 is None: + logger.error("Failed to invite vendor contact.") + else: + logger.error("POST request failed to invite vendor contact, see response >>> %s %s \n %s" % ( + r1.status_code, r1.reason, str(r1.content, 'utf-8'))) + raise + + @staticmethod + def edit_next_step(user_content, ns_uuid): + r1 = None + postURL = settings.ICE_EM_URL + '/v1/engmgr/nextsteps/' + ns_uuid + \ + '/engagement/' + user_content['engagement_uuid'] + '/modify/' + logger.debug("Put next step URL: " + postURL) + headers = dict() # Create header for post request. + headers['Content-type'] = 'application/json' + headers['Authorization'] = user_content['session_token'] + data = dict() # Create JSON data for post request. + data['files'] = [] + data['assigneesUuids'] = [user_content['uuid']] + data['duedate'] = str(datetime.date.today()) + data['description'] = "API edit next step test " + \ + Helper.rand_string('randomString') + try: + r1 = requests.put( + postURL, json=data, headers=headers, verify=False) + Helper.internal_assert_boolean(r1.status_code, 202) + logger.debug("Next step was edited successfully!") + except: + if r1 is None: + logger.error("Failed to edit next step uuid: " + ns_uuid) + else: + logger.error("Failed to edit next step uuid: " + ns_uuid + + ", see response >>> %s %s" % (r1.status_code, r1.reason)) + raise + + @staticmethod + def get_export_dasboard_excel(token, keywords=""): + postUrl = settings.EM_REST_URL + \ + "engagement/export/?stage=All&keyword=" + keywords + headers = {"Authorization": token} + r1 = requests.get(postUrl, headers=headers, verify=False) + Helper.internal_assert(r1.status_code, 200) + if (r1.status_code == 200): + logger.debug("APIUser activated successfully!") + return r1.content + else: + raise Exception( + "Failed to activate user >>> %s %s" % (r1.status_code, r1.reason)) + return False + + @staticmethod + def create_engagement(wait_for_gitlab=True): + user_content = APIUser.create_new_user() + APIUser.activate_user( + user_content['uuid'], user_content['user']['activation_token']) + token = APIUser.login_user(user_content['email']) + vf_content = json.loads(APIVirtualFunction.create_vf(token)) + user_content['vfName'] = vf_content['name'] + user_content['vf_uuid'] = vf_content['uuid'] + user_content['target_aic'] = vf_content['deployment_target']['version'] + # <-- ECOMP RELEASE + user_content['ecomp_release'] = vf_content[ + 'ecomp_release']['name'] + user_content['vnf_version'] = vf_content['version'] + if(vf_content['vendor']['name'] == "AT&T"): + user_content['vendor'] = "AT&T" + else: + user_content['vendor'] = vf_content['vendor']['name'] + user_content['vendor_uuid'] = vf_content['vendor']['uuid'] + user_content['engagement_manual_id'] = vf_content[ + 'engagement']['engagement_manual_id'] + user_content['target_lab_entry_date'] = vf_content[ + 'target_lab_entry_date'] + user_content['el_email'] = vf_content[ + 'engagement']['reviewer']['email'] + user_content['el_name'] = vf_content[ + 'engagement']['reviewer']['full_name'] + user_content['pr_email'] = vf_content[ + 'engagement']['peer_reviewer']['email'] + user_content['pr_name'] = vf_content[ + 'engagement']['peer_reviewer']['full_name'] + user_content['engagement_uuid'] = vf_content['engagement']['uuid'] + user_content['session_token'] = 'token ' + token + user_content['engagement'] = vf_content['engagement'] + user_content['vfStage'] = vf_content['engagement']['engagement_stage'] + + return user_content + + @staticmethod + def set_eng_stage(user_content, requested_stage): + token = APIUser.login_user(user_content['el_email']) + r1 = None + putUrl = Constants.Default.URL.Engagement.SingleEngagement.TEXT + \ + user_content['engagement_uuid'] + "/stage/" + str(requested_stage) + headers = dict() # Create header for post request. + headers['Content-type'] = 'application/json' + headers['Authorization'] = 'token ' + token + try: + r1 = requests.put( + putUrl, headers=headers, verify=False) + Helper.internal_assert(r1.status_code, 202) + logger.debug( + "Engagement stage was successfully changed to " + str(requested_stage) + "!") + content = r1.content[1:-1] + return content + except: + if r1 is None: + logger.debug("Failed to set eng stage >>> request failed!") + else: + logger.debug( + "Failed to set eng stage >>> %s %s \n %s" % (r1.status_code, r1.reason, str(r1.content, 'utf-8'))) + raise + + @staticmethod + def update_aic_version(eng_uuid, aic_version_uuid, session_token): + r1 = None + putURL = Constants.Default.URL.Engagement.EngagementOperations.TEXT + \ + eng_uuid + '/deployment-targets/' + aic_version_uuid + logger.debug("Put next step URL: " + putURL) + headers = dict() # Create header for post request. + headers['Content-type'] = 'application/json' + headers['Authorization'] = session_token + try: + r1 = requests.put(putURL, headers=headers, verify=False) + Helper.internal_assert_boolean(r1.status_code, 200) + logger.debug("AIC version has changed!") + except: + if r1 is None: + msg = "Failed to edit AIC version" + else: + msg = "Failed to edit AIC version, see response >>> %s %s" % ( + r1.status_code, r1.reason) + raise msg + + @staticmethod + def update_ecomp_release(eng_uuid, ecomp_release_uuid, session_token): + r1 = None + putURL = Constants.Default.URL.Engagement.EngagementOperations.TEXT + \ + eng_uuid + '/ecomp-releases/' + ecomp_release_uuid + logger.debug("Put next step URL: " + putURL) + headers = dict() # Create header for post request. + headers['Content-type'] = 'application/json' + headers['Authorization'] = session_token + try: + r1 = requests.put(putURL, headers=headers, verify=False) + Helper.internal_assert_boolean(r1.status_code, 200) + logger.debug("AIC version has changed!") + except: + if r1 is None: + msg = "Failed to update ECOMP release" + else: + msg = "Failed to update ECOMP release, see response >>> %s %s" % ( + r1.status_code, r1.reason) + raise msg diff --git a/services/constants.py b/services/constants.py new file mode 100644 index 0000000..0be529f --- /dev/null +++ b/services/constants.py @@ -0,0 +1,1036 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +from django.conf import settings + + +class ServiceProvider: + PROGRAM_NAME = "VVP" + MainServiceProvider = "ServiceProvider" + email = "example.com" + + +class Constants: + + class FEGeneral: + + class CSS: + H2 = 'h2' + + class Paths: + + class SSH: + PATH = "/root/.ssh/" + + class LocalGitFolder: + PATH = "/tmp/git_work/" + + class DBConstants: + RETRIES_NUMBER = 120 + + class Engagement: + + AIC = 'aic_instantiation_time' + + class Queries: + COUNT = "COUNT(*)" + + class IceTables: + NOTIFICATION = "ice_notification" + USER_PROFILE = "ice_user_profile" + ENGAGEMENT = "ice_engagement" + CHECKLIST = "ice_checklist" + RECENT = "ice_recent_engagement" + NEXT_STEP = "ice_next_step" + + class ChecklistStates: + + class Pending: + TEXT = "pending" + + class Automation: + TEXT = "automation" + + class Review: + TEXT = "review" + + class Archive: + TEXT = "archive" + + class FEConstants: + RETRIES_NUMBER = 120 + + class GitLabConstants: + RETRIES_NUMBER = 60 + + class RGWAConstants: + RETRIES_NUMBER = 100 + BUCKET_RETRIES_NUMBER = 180 + + class ChecklistSignalsConstants: + RETRIES_NUMBER = 10 + + class Users: + + class Admin: + EMAIL = "admin@example.com" + FULLNAME = "admin bogus user" + + class AdminRO: + EMAIL = "admin_ro@example.com" + + class LongEmailLengthStandardUser: + EMAIL = "50charslengthemailofstandarduserforinvite@example.com" + + class Toast: + ID = "toast-successfully-message" + CMS_ID = "announcement-successfully-message" + CSS = "html.ng-scope" + + class Cms: + Toast_title_id = "toast-title-id" + Toast_description = "toast-description" + Test_addDT_close_modal_button = "close-modal-button" + Documentation = "documentation" + Tooltip_title = "tooltip-title" + Tooltip_description = "tooltip-description" + SearchDocumentation = "search-doc" + DocumentationPageContent = ".page-content > p" + + class Template: + + class Heat: + TEXT = "Heat Templates" + + class Subtitle: + + class SelectTemplateTitle: + TEXT = "please-select" + + class SubmitButton: + CSS = "button.btn.btn-primary" + ID = "submit-modal" + + class Home: + + class Logo: + ID = "logo" + + class Title: + ID = "home-heading" + TEXT = "Welcome to " + ServiceProvider.PROGRAM_NAME + + class GetStarted: + LINK_TEXT = "Get Started" + TEXT = "Get Started" + + class Collaborate: + ID = "collaborate" + XPATH = "//div[3]/div/h3" + TEXT = "Collaborate" + + class Validate: + XPATH = "//div[2]/div/h3" # FIXME: change xpath + TEXT = "Validate" + + class Incubate: + # FIXME: change xpath + XPATH = "//section[@id='boxes']/div/div/div/h3" + TEXT = "Incubate" + + class Login: + + class Signup: + LINK_TEXT = "Sign Up" + + class Title: + CSS = "h1.ng-binding" + TEXT = "Login" + + class SubTitle: + CSS = "h2.ng-binding" + TEXT = "Please use the form below to login" + + class Email: + NAME = "email" + + class Password: + NAME = "password" + + class Error: + CSS = "div.form-group.has-error > div.ice-form-error > span" + TEXT = "Password is a required field." + + class ResetPassword: + LINK_TEXT = "Reset your password?" + TEXT = "Reset your password?" + + class DontHaveAccount: + ID = "id-dont-have-an-account" + TEXT = "Don't have an account?" + + class Toast: + TEXT = "User or Password does not match" + + class Signup: + + class Title: + CSS = "h1.ng-binding" + TEXT = "Sign Up" + + class SubTitle: + CSS = "h2.ng-binding" + TEXT = "Please use the form to Sign Up to " + \ + ServiceProvider.PROGRAM_NAME + + class Company: + NAME = "company" + + class FullName: + NAME = "fullname" + + class Email: + NAME = "email" + + class Phone: + NAME = "phone" + + class Password: + NAME = "password" + + class RegularEmail: + XPATH = "//input[@type='checkbox']" # FIXME: Change XPath + + class AcceptTerms: + XPATH = "(//input[@type='checkbox'])[2]" # FIXME: Change XPath + + class Toast: + + class Captcha: + TEXT = "Please fill CAPTCHA!" + + class NotMainVendor: + TEXT = "Email address should be with service provider domain for signees that their company =" \ + + ServiceProvider.MainServiceProvider + + class HaveAccount: + LINK_TEXT = "Already have an account?" + TEXT = "Already have an account?" + + class ActivateAccount: + + class Title: + CSS = "h1.ng-binding" + TEXT = "Activate Your Account" + + class SubTitle: + CSS = "h2.ng-binding" + TEXT = "Please follow the instructions below to activate your account." + + class Toast: + TEXT = "Please activate your account first" + + class ResetPassword: + + class Toast: + + class Success: + TEXT = "An email with detailed instructions on how to reset your password was sent to your Email." + + class Title: + CSS = "h1.ng-binding" + TEXT = "Reset Your Password" + + class SubTitle: + CSS = "h2.ng-binding" + TEXT = "Please follow the instructions below to reset your password" + + class Button: + TEXT = "Send Instructions" + + class Email: + NAME = "email" + + class UpdatePassword: + + class Title: + CSS = "h1.ng-binding" + TEXT = "Update Your Password" + + class SubTitle: + CSS = "h2.ng-binding" + TEXT = "Please follow the instructions below to update your password" + + class Password: + NAME = "password" + + class ConfirmPassword: + NAME = "confirm_password" + + class Button: + TEXT = "Update Password" + + class Toast: + TEXT = "Password was updated Successfully!" + + class Dashboard: + + class Modal: + TITLE_ID = "modal-title" + CLOSE_BUTTON_ID = "close-modal-button" + + class Default: + DASHBOARD_ID = "dashboard" + STATISTICS = "statistics" + + class Checklist: + + TITLE = "Checklist:" + + class ChecklistDefaultNames: + HEAT_TEMPLATES = "Heat Templates" + IMAGE_VALIDATION = "Image Validation" + AIC_INSTANTIATION = "AIC Instantiation" + ASDC_ONBOARDING = "ASDC Onboarding" + + class Name: + ID = "cl-name-id" + + class AuditLog: + ID = "audit-log" + + class LastLocalAuditLog: + CSS = "#audit-log-list > li:last-child p" + + class AuditLogList: + ID = "audit-log-list" + + class JenkinsLog: + + ID = "jenkins-log" + + class Modal: + + class Title: + ID = "general-log-modal-title-id" + TEXT = "Jenkins log" + + class Body: + ID = 'general-log-modal-body-id' + TEXT_SAMPLE = 'Started by user admin' + BUILD_IDENTIFIER = '/bin/sh /tmp/' + + class LineItem: + + class Approve: + CSS = "li.approved-cl-btn" + + class Deny: + CSS = "li.denied-cl-btn" + + class Approve: + pass + + class Reject: + ID = "state-actions-btn-reject" + + class Modal: + + class Button: + ID = "reject-state" + TEXT = "Reject" + + class Comment: + NAME = "entry_comment" + + class AddNS: + TITLE = "Add Next Steps" + ID = "state-actions-btn-add-next-steps" + CSS = "span.font_header" + + class GeneralPrompt: + + class UpperTitle: + ID = "general-prompt-upper-headline" + + class Title: + ID = "general-prompt-title" + + class ApproveButton: + ID = "general-prompt-approve-btn" + + class CancelButton: + ID = "general-prompt-cancel-btn" + + class Wizard: + + class Open: + CSS = "div[modal-animation='true']" + CLASS_NAME = "getting-started-wizard" + + class Title: + CSS = "h2.modal-title.ng-binding" + + class CloseButton: + ID = "close-wizard-button" + + class AddVF: + + class Title: + TEXT = "Add a VF" + + class AIC_Version: + TEXT = "aic-version" + + class ECOMP_Release: + TEXT = "ecomp-release" + + class AddVendorContact: + + class Title: + TEXT = "Add Vendor Contact" + + class InviteTeamMembers: + + class Title: + NAME = "Invite Team Members" + TEXT = "Invite Team Members" + + class Button: + TEXT = "Send invitations" + + class AddSSHKey: + + class Title: + NAME = "Add SSH Key" + TEXT = "Add SSH Key" + + class TextBox: + NAME = "key" + + class ActivateMsg: + + class Success: + TEXT = "You have successfully activated your account!" + + class Fail: + TEXT = "Please activate your account first" + + class Avatar: + ID = "avatar" + + class Account: + LINK_TEXT = "Account" + + class Title: + CSS = "h2.ng-scope" + TEXT = "Account" + + class FullName: + NAME = "fullname" + + class Email: + NAME = "email" + + class Phone: + NAME = "phone" + + class Company: + NAME = "company" + + class SSHKey: + NAME = "ssh_key" + + class UpdateFailed: + # TEXT = "Something went wrong while trying to update user account" + TEXT = "Updating SSH Key failed due to invalid key." + + class Update: + + class Success: + TEXT = "Account was updated successfully!" + + class RGWA: + + class Key: + TITLE_ID = "access-key-title" + KEY_ID = "access-key-value" + + class Secret: + TITLE_ID = "access-secret-title" + SECRET_ID = "access-secret-value" + BUTTON_ID = "show-access-secret" + SECRET_TEXT = "•••••••••••••••" + + class UserProfileSettings: + ID = 'user-profile-settings' + TitleID = 'user-profile-settings-title' + TitleText = 'Settings' + ReceiveEmailsID = 'receive-emails' + ReceiveNotificationsID = 'receive-notifications' + ReceiveEmailEveryTimeID = 'receive-emails-every-time' + ReceiveDigestEmailID = 'receive-digest-emails' + UpdateButtonID = 'update-account-user-profile-settings' + + class Notifications: + LINK_TEXT = "Notifications" + + class NotificationColumn: + ID = "table-col-" + + class DeleteNotification: + ID = "del-notification-" + + class Count: + ID = "notifications-count" + RETRIES_NUMBER = 20 + + class Title: + ID = "notifications" + TEXT = "Notifications" + + class Admin: + LINK_TEXT = "Admin" + + class Title: + CSS = "h1.caption" + TEXT = "Admin" + ID = "admin-toolbar-link" + + class Logout: + LINK_TEXT = "Logout" + + class Feedback: + ID = "feedback-toolbar-link" + + class FeedbackModal: + SAVE_BTN_ID = "add-feedback-save-button" + + class Statuses: + ID = "logo" + + class Body: + ID = "search-results" + TEXT = "Export to Excel >>" + + class Title: + ID = "dashboard-title" + TEXT = "Statuses" + + class FilterDropdown: + ID = "search-filter-stage" + + class SearchBox: + ID = "search-filter-keyword" + + class SearchFilters: + ID = "search-filters" + + class AssignedNS: + ID = "next-steps-header" + + class Statistics: + + class Title: + ID = "statistics-header" + TEXT = "Statistics" + + class FilterDropdown: + CSS = "#statistics-header > .search-filters > .search-filter-stage" + + class ValidationsNumber: + ID = "id-validations-num" + + class EngagementsNumber: + ID = "id-engagements-num" + + class News: + + class Title: + ID = "news-and-announcements-header" + TEXT = "News & Announcements" + + class List: + ID = "news-and-announcements-list" + TEXT = "There are no posts." + + class ExportExcel: + ID = "export-to-csv" + TEXT = "Export to Excel >>" + + class Overview: + + class AdminDropdown: + ID = "admin-actions-dropdown" + + class ArchiveEngagement: + LINK_TEXT = "Archive" + + class Wizard: + + class Title: + ID = "archive-engagement-title" + TEXT = "Archive Engagement" + + class Reason: + NAME = "reason" + + class ChangeReviewer: + LINK_TEXT = "Change Reviewer" + + class Wizard: + + class Title: + ID = "archive-engagement-title" + TEXT = "Select Engagement Lead" + + class Select: + NAME = "selected-user" + + class Toast: + TEXT = "Reviewer updated successfully." + + class ChangePeerReviewer: + LINK_TEXT = "Change Peer Reviewer" + + class Wizard: + + class Title: + ID = "archive-engagement-title" + TEXT = "Select Engagement Lead" + + class Toast: + TEXT = "Peer reviewer updated successfully." + + class UpdateStatus: + LINK_TEXT = "Update Status" + PROGRESS = "progress" + PROGRESS_CSS = 'input[name="progress"]' + TARGET = 'vm.engagement.target_completion_date' + HEAT = 'vm.engagement.heat_validated_time' + IMAGE_SACN = 'vm.engagement.image_scan_time' + AIC = 'vm.engagement.aic_instantiation_time' + ASDC = 'vm.engagement.asdc_onboarding_time' + STATUS = "status" + SUBMIT = 'button[type="submit"]' + SUCCESS_MSG = 'Engagement status updated successfully.' + + class BucketURL: + ID = "bucket-url" + TEXT = "STORAGE BUCKET: " + + class GitURL: + ID = "git-url" + + class Title: + ID = "engagement-title" + + class Star: + ID = "star-engagement-action" + + class Stage: + + class Approve: + XPATH = "//button[@type='submit']" # FIXME: Change XPath + + class Deny: + # FIXME: Change XPath + XPATH = "(//button[@type='submit'])[2]" + + class Set: + ID = "set-stage-" + + class Progress: + + class ValidationsDates: + + AIC_ID = 'aic-instantiation-time' + HEAT_ID = 'heat-validated-time' + IMAGE_ID = 'image-scan-time' + ASDC_ID = 'asdc-onboarding-time' + VALIDATION_DATES_ARRAY = [ + AIC_ID, HEAT_ID, IMAGE_ID, ASDC_ID] + + class VnfVersion: + CLASS = "vnf_version_value" + + class Percent: + ID = "progress-percentage" + TEXT = "0 %" + + class Change: + ID = "edit-change-progress" + NUMBER = "55" + TEXT = "55 %" + + class Wizard: + NAME = "progress" + + class Title: + TEXT = "Specify Progress in %" + + class Button: + TEXT = "Save" + + class Status: + + class Header: + ID = "#engagement-status-header > span" + + class Add: + CSS = "i.add-engagement-status" + + class Edit: + CSS = "i.edit-engagement-status" + + class Description: + ID = "status-description" + + class LastUpdated: + ID = "status-update-details" + + class TeamMember: + ID = "team-members-plus-button-id" + MEMBER_ID = "team-member-%s" + + class Title: + ID = "team-member-title" + + class RemoveUser: + ID = "remove-member" + + class Title: + TEXT = "Remove user from engagement team: %s" + + class Message: + TEXT = "Are you sure you would like to remove the user out of the team members?" + + class NextSteps: + + class FilterByFileDropDown: + ID = "selected-file-filter-dropdown" + ANY_FILE_LINK_TEXT = "Any file" + FILE0_LINK_TEXT = "file0.yaml" + FILE1_LINK_TEXT = "file1.yaml" + FILE2_LINK_TEXT = "file2.yaml" + + class StateDropDown: + ID = "selected-state-filter-dropdown" + INCOMPLETE_LINK_TEXT = "Incomplete" + COMPLETED_LINK_TEXT = "Completed" + + class Add: + TITLE = "Engagement:" + ID = "add-next-step-button" + + class Title: + CSS = "h2" + TEXT = "Add Next Steps" + + class Description: + ID = "description" + STEP_DESC_ID = "step-description-" + + class Button: + TEXT = "Submit Next Steps" + + class AssociatedFiles: + ID = "associated-files-list" + ALL_FILES_SELECTED = "3 files selected" + SELECT_ALL_FILES_NAME = "Select All" + + class AssociatedFiles: + ID = "associated-files" + EmptyMsgID = "associated-files-empty-msg" + EmptyMsg = "There are no files for this next step" + FileId = "file0" + + class DetailedView: + ID = "detailed-view-" + + class DeploymentTarget: + ID = "deployment-targets" + TEXT = "Deployment Targets" + TITLE = "Add Deployment Target" + SAVE = "add-dt-save-button" + CSS = "span.col-md-10.ng-binding" + ID_REMOVE_DTS = "remove-dts-" + + class AddDeploymentTargetButton: + ID = "add-dt" + + class VirtualFunctionComponents: + ID = "virtual-function-components" + TEXT = "Virtual Function Components" + + class ValidationDetails: + PLUS = "update-validation-details" + TITLE = "Validation Details (ECOMP, AIC, VF Version)" + SAVE = "edit-validation-setails-save-button" + ID = "vd-title" + TEXT = "Validation Details" + + class TargetAICVersion: + ID = "target-aic-version-headline" + TEXT = "Target AIC Version:" + AIC3 = "AIC 3.0" + + class ECOMPRelease: + ID = "ecomp-release-headline" + TEXT = "ECOMP Release:" + ID_ECOMP = "ecomp-select-options-" + UNKNOW = "Unknown" + + class VFVersion: + ID = "vf-version-headline" + TEXT = "VF Version:" + ID_VERSION = "id-vf-version" + VF_VERSION_ID = "vf_version_" + + class TargetLabEntry: + ID = "target-lab-entry" + TEXT = "Target Lab Entry" + CSS = "#target-lab-entry-header > span" + CHANGE = "change-lab-entry-date" + INPUT_CSS = '.md-datepicker-input' + CONTENT_CSS = "h4.target-lab-entry-content" + + class Add: + ID = "add-dt" + + class VFC: + TEXT = "Virtual Function Components" + ID = "visible-dts-" + + class Add: + ID = "add-vfc" + + class Remove: + ID = "remove-vfc-" + + class Save_button: + ID = "add-vfc-save-button" + + class Choose_Company: + ID = "add-vfc-choose-company" + + class AIC: + TEXT = "Target AIC Version" + ID = "aic_version_" + + class Edit: + ID = "test_AIC_Version_Edit" + + class Confirm: + ID = "test_AIC_Version_Update" + + class Decline: + ID = "test_AIC_Version_Remove" + + class Dropdown: + ID = "aic-version-select" + + class TwoPointFive: + ID = "aic_select_options_2.5" + TEXT = "2.5" + + class Three: + ID = "aic_select_options_3.0" + TEXT = "3.0" + + class ThreePointFive: + ID = "aic_select_options_3.5" + TEXT = "3.5" + + class Four: + ID = "aic_select_options_4.0" + TEXT = "4.0" + + class UniversalVersion: + ID = "aic_select_options_%s" + + class NoVersion: + ID = "aic_select_options_No version number available" + TEXT = "No version number available" + + class ECOMP: + ID = "ecomp_version_" + + class Edit: + ID = "test_ECOMP_Release_Edit" + + class Confirm: + ID = "test_ECOMP_Release_Update" + + class Decline: + ID = "test_ECOMP_Release_Remove" + + class Dropdown: + ID = "ecomp-release-select" + + class Unknown: + ID = "ecomp-select-options-Unknown" + + class UniversalRelease: + ID = "ecomp-select-options-%s" + + class LeftPanel: + + class Title: + CSS = "h1.caption" + TEXT = "Engagements" + + class AddEngagement: + ID = "add-engagement" + + class SearchBox: + ID = "search-eng" + + class Results: + ID = "search-%s" # %s --> VF name + CSS = "span.search-engagement-name.ng-binding" + XPATH = "//input[@type='text']" + + class NoResults: + ID = "search-no-results" + + class CreateChecklist: + ID = "btn-create-checklist" # "btn-modal-update-checklist" + + class EditChecklistTemplate: + SUCCESS_SAVE_MSG = "Template was saved successfully." + SAVE_BTN = "Save" + HEAT = "Editing Heat" + SAVE_BTN_ID = "save-button" + APPROVE_BTN_ID = "general-prompt-approve-btn" + SUCCESS_ID = "toast-successfully-message" + APPROVE_BTN_TITLE_ID = "general-prompt-title" + APPROVE_BTN_TITLE_TEXT = "Are you done editing?" + CL_TEMPLATE_SAVED_TXT = "Template was saved successfully." + FIRST_SECTION_ID = "edit-section-btn-0" + FIRST_SECTION_INPUT_ID = "edit-section-input-0" + REJECT_BTN_ID = "state-actions-btn-reject" + ADD_LINE_ITEM_BTN = "add-lineitem-btn" + EDIT_LINE_ITEM_BTN = "edit-lineitem-btn" + EDIT_LINE_ITEM_NAME = "edit-line-item-name-input" + LINE_ITEM_DESC_TEXT_BOX = "edit-lineitem-description" + EDIT_LINE_ITEM_DESC = "edit-lineitem-description-input" + FIRST_LINE_ITEM_ID = "select-lineitem-btn-0.0" + WYSIWYG_BUTTON_BOLD = "//button[@type='button']" + DASHBOARD_ID = "dashboard" + SEARCH_ENG_ID = "search-eng" + DELETE_LINE_ITEM = "delete-lineitem-btn" + + class DefaultChecklistTemplateParametrs: + DEFAULT_FIRST_SECTION_VALUE = "External References" + + class EngagementStages: + INTAKE = "Intake" + ACTIVE = "Active" + VALIDATED = "Validated" + COMPLETED = "Completed" + ALL = "All" + + class Default: + + class TestPrefix: + Test = "test_" + Center = "center-" + + class Password: + TEXT = "iceusers" + + class NewPass: + TEXT = "1234" + + class Phone: + TEXT = "+972-50-555-5555" + + class LoginURL: + TEXT = settings.ICE_PORTAL_URL + "/#/login" + + class DashbaordURL: + TEXT = settings.ICE_PORTAL_URL + "/#/dashboard/dashboard" + + class OverviewURL: + TEXT = settings.ICE_PORTAL_URL + "/#/dashboard/overview" + + class InviteURL: + + class Login: + TEXT = settings.ICE_PORTAL_URL + "/#/login?invitation=" + + class Signup: + TEXT = settings.ICE_PORTAL_URL + "/#/signUp?eng_uuid=" + + class URL: + + class Engagement: + + class EngagementOperations: + TEXT = settings.ICE_EM_URL + '/v1/engmgr/engagement/' + + class SingleEngagement: + TEXT = settings.ICE_EM_URL + \ + '/v1/engmgr/single-engagement/' + + class Checklist: + TEXT = settings.ICE_EM_URL + '/v1/engmgr/engagement/' + + class Get: + TEXT = settings.ICE_EM_URL + '/v1/engmgr/checklist/' + + class Create: + TEXT = settings.ICE_EM_URL + '/v1/engmgr/checklist/' + + class Update: + TEXT = settings.ICE_EM_URL + '/v1/engmgr/checklist/' + + class Rest: + TEXT = settings.EM_REST_URL + "checklist/" + + class GitLab: + + class Projects: + TEXT = settings.GITLAB_URL + "api/v3/projects/" + + class Users: + TEXT = settings.GITLAB_URL + "api/v3/users/" + + class BlockUI: + CSS = "div.block-ui-message.ng-binding" diff --git a/services/database/__init__.py b/services/database/__init__.py new file mode 100644 index 0000000..30d7152 --- /dev/null +++ b/services/database/__init__.py @@ -0,0 +1,38 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. diff --git a/services/database/__pycache__/__init__.cpython-36.pyc b/services/database/__pycache__/__init__.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..12ed104 --- /dev/null +++ b/services/database/__pycache__/__init__.cpython-36.pyc diff --git a/services/database/__pycache__/db_bridge.cpython-36.pyc b/services/database/__pycache__/db_bridge.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..06fb01e --- /dev/null +++ b/services/database/__pycache__/db_bridge.cpython-36.pyc diff --git a/services/database/__pycache__/db_checklist.cpython-36.pyc b/services/database/__pycache__/db_checklist.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..81e29bd --- /dev/null +++ b/services/database/__pycache__/db_checklist.cpython-36.pyc diff --git a/services/database/__pycache__/db_cms.cpython-36.pyc b/services/database/__pycache__/db_cms.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..783d2f8 --- /dev/null +++ b/services/database/__pycache__/db_cms.cpython-36.pyc diff --git a/services/database/__pycache__/db_general.cpython-36.pyc b/services/database/__pycache__/db_general.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..c39ce12 --- /dev/null +++ b/services/database/__pycache__/db_general.cpython-36.pyc diff --git a/services/database/__pycache__/db_user.cpython-36.pyc b/services/database/__pycache__/db_user.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..46d136e --- /dev/null +++ b/services/database/__pycache__/db_user.cpython-36.pyc diff --git a/services/database/__pycache__/db_virtual_function.cpython-36.pyc b/services/database/__pycache__/db_virtual_function.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..8a46fb8 --- /dev/null +++ b/services/database/__pycache__/db_virtual_function.cpython-36.pyc diff --git a/services/database/db_bridge.py b/services/database/db_bridge.py new file mode 100644 index 0000000..fc765c7 --- /dev/null +++ b/services/database/db_bridge.py @@ -0,0 +1,60 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +class DBBridge: + + """ + This class helps to use functions inside classes with circular import (dependencies). + Use this class only when there is circular import in one of the DB services. + """ + + @staticmethod + def select_personal_next_step(user_email): + """select_personal_next_step: Originally can be found under DBUser class.""" + from services.database.db_user import DBUser + return DBUser.select_personal_next_step(user_email) + + @staticmethod + def helper_rand_string(type, num=""): + from services.helper import Helper + return Helper.rand_string(type, num) + + @staticmethod + def helper_internal_assert(arg1, arg2): + from services.helper import Helper + return Helper.internal_assert(arg1, arg2) diff --git a/services/database/db_checklist.py b/services/database/db_checklist.py new file mode 100644 index 0000000..15851cf --- /dev/null +++ b/services/database/db_checklist.py @@ -0,0 +1,386 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +import time +from uuid import uuid4 + +from django.utils import timezone +import psycopg2 + +from services.constants import Constants +from services.database.db_general import DBGeneral +from services.logging_service import LoggingServiceFactory +from services.session import session + + +logger = LoggingServiceFactory.get_logger() + +class DBChecklist: + + @staticmethod + def select_where_approval_state(queryColumnName, queryTableName, whereParametrType, whereParametrValue, fetchNum): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = dbConn + cur = dbConn.cursor() + queryStr = "select %s from %s Where %s = '%s' and state = 'approval';" % ( + queryColumnName, queryTableName, whereParametrType, whereParametrValue) + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + if (fetchNum == 0): + result = str(cur.fetchall()) + elif (fetchNum == 1): + result = str(cur.fetchone()) + if(result.find("',)") != -1): # formatting strings e.g uuid + result = result.partition('\'')[-1].rpartition('\'')[0] + elif(result.find(",)") != -1): # formatting ints e.g id + result = result.partition('(')[-1].rpartition(',')[0] + dbConn.close() + logger.debug("Query result: " + str(result)) + if result == None: + errorMsg = "select_where_approval_state FAILED " + logger.error(errorMsg) + raise + return result + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "select_where_approval_state FAILED " + raise Exception(errorMsg, "select_where_approval_state FAILED") + + @staticmethod + def select_where_pr_state(queryColumnName, queryTableName, whereParametrType, whereParametrValue, fetchNum): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = dbConn + cur = dbConn.cursor() + queryStr = "select %s from %s Where %s = '%s' and state = 'peer_review';" % ( + queryColumnName, queryTableName, whereParametrType, whereParametrValue) + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + if (fetchNum == 0): + result = str(cur.fetchall()) + elif (fetchNum == 1): + result = str(cur.fetchone()) + if(result.find("',)") != -1): # formatting strings e.g uuid + result = result.partition('\'')[-1].rpartition('\'')[0] + elif(result.find(",)") != -1): # formatting ints e.g id + result = result.partition('(')[-1].rpartition(',')[0] + dbConn.close() + if result == None: + errorMsg = "select_where_pr_state FAILED " + logger.error(errorMsg) + raise + logger.debug("Query result: " + str(result)) + return result + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "select_where FAILED " + raise Exception(errorMsg, "select_where") + + @staticmethod + def select_where_cl_not_archive(queryColumnName, queryTableName, whereParametrType, whereParametrValue, fetchNum): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = dbConn + cur = dbConn.cursor() + queryStr = "select %s from %s Where %s = '%s' and state != 'archive';" % ( + queryColumnName, queryTableName, whereParametrType, whereParametrValue) + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + if (fetchNum == 0): + result = str(cur.fetchall()) + elif (fetchNum == 1): + result = str(cur.fetchone()) + if(result.find("',)") != -1): # formatting strings e.g uuid + result = result.partition('\'')[-1].rpartition('\'')[0] + elif(result.find(",)") != -1): # formatting ints e.g id + result = result.partition('(')[-1].rpartition(',')[0] + dbConn.close() + logger.debug("Query result: " + str(result)) + return result + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "select_where FAILED " + raise Exception(errorMsg, "select_where") + + @staticmethod + def select_native_where(queryColumnName, queryTableName, whereParametrType, whereParametrValue, fetchNum): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = dbConn + cur = dbConn.cursor() + queryStr = "select %s from %s Where %s = '%s';" % ( + queryColumnName, queryTableName, whereParametrType, whereParametrValue) + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + if (fetchNum == 0): + result = str(cur.fetchall()) + elif (fetchNum == 1): + result = str(cur.fetchone()) + if(result.find("',)") != -1): # formatting strings e.g uuid + result = result.partition('\'')[-1].rpartition('\'')[0] + elif(result.find(",)") != -1): # formatting ints e.g id + result = result.partition('(')[-1].rpartition(',')[0] + dbConn.close() + logger.debug("Query result: " + str(result)) + return result + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "select_where FAILED " + raise Exception(errorMsg, "select_where") + + @staticmethod + def update_checklist_to_review_state(queryTableName): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = dbConn + cur = dbConn.cursor() + queryStr = "UPDATE ice_checklist SET state='review' Where name= '%s' and state= 'pending';" % ( + queryTableName) + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + dbConn.commit() + dbConn.close() + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "Could not Update User" + raise Exception(errorMsg, "Update") + + @staticmethod + def update_all_decisions_to_approve(whereParametrValue): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = dbConn + cur = dbConn.cursor() + queryStr = "UPDATE ice_checklist_decision SET review_value='approved' , peer_review_value='approved' Where checklist_id = '%s';" % ( + whereParametrValue) + logger.debug(queryStr) + cur.execute(queryStr) + dbConn.commit() + logger.debug("Query : " + queryStr) + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "Could not Update User" + logger.debug(e) + raise Exception(errorMsg, "Update") + finally: + dbConn.close() + + @staticmethod + def is_archive(checklistName): + try: + result = False + # Fetch all AT&T user ID. + checklist_ids = DBGeneral.select_where( + "uuid", "ice_checklist", "name", checklistName, 0) +# checklist_ids = DBGeneral.list_format(checklist_ids) + for checklist_id in checklist_ids: # Second Example + if isinstance(checklist_id, tuple): + checklist_id = checklist_id[0] + state = DBGeneral.select_where( + "state", "ice_checklist", "uuid", checklist_id, 1) + if state == "archive": + result = True + break + return result + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "is_archive FAILED " + raise Exception(errorMsg, "is_archive") + + @staticmethod + def get_pr_email(checklistUuid): + try: + # Fetch one AT&T user ID. + owner_id = DBChecklist.select_where_pr_state( + "owner_id", "ice_checklist", "uuid", checklistUuid, 1) + engLeadEmail = DBGeneral.select_where( + "email", "ice_user_profile", "id", owner_id, 1) + logger.debug("get_pr_email = " + engLeadEmail) + return engLeadEmail + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "get_pr_email FAILED " + str(e) + raise Exception(errorMsg, "get_pr_email") + + @staticmethod + def get_admin_email(checklistUuid): + try: + owner_id = DBChecklist.select_where_approval_state( + "owner_id", "ice_checklist", "uuid", checklistUuid, 1) # Fetch one AT&T user ID. + engLeadEmail = DBGeneral.select_where( + "email", "ice_user_profile", "id", owner_id, 1) + logger.debug("get_admin_email = " + engLeadEmail) + return engLeadEmail + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "get_admin_email FAILED " + raise Exception(errorMsg, "get_admin_email") + + @staticmethod + def get_owner_email(checklistUuid): + try: + # Fetch one AT&T user ID. + owner_id = DBChecklist.select_native_where( + "owner_id", "ice_checklist", "uuid", checklistUuid, 1) + engLeadEmail = DBGeneral.select_where( + "email", "ice_user_profile", "id", owner_id, 1) + logger.debug("getPreeReviewerEngLeadEmail = " + engLeadEmail) + return engLeadEmail + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "get_admin_email FAILED " + raise Exception(errorMsg, "get_owner_email") + + @staticmethod + def update_decisions(checklistUuid, checklistName): + checklistTempid = DBGeneral.select_where( + "template_id", "ice_checklist", "name", checklistName, 1) + checklistLineItems = DBGeneral.select_where_and( + "uuid", "ice_checklist_line_item", "line_type", "auto", "template_id", checklistTempid, 0) + for lineItem in checklistLineItems: + setParametrType2 = "peer_review_value" + setParametrValue2 = "approved" + whereParametrType2 = "lineitem_id" + whereParametrValue2 = lineItem + DBGeneral.update_where_and("ice_checklist_decision", "review_value", checklistUuid, "approved", + "checklist_id", setParametrType2, setParametrValue2, whereParametrType2, whereParametrValue2) + + @staticmethod + def checkChecklistIsUpdated(): + query = "select uuid from ice_checklist_section where template_id in (select template_id from ice_checklist_template where name='{template_name}') and name='{section_name}'".format( + template_name=Constants.Dashboard.LeftPanel.EditChecklistTemplate.HEAT, section_name=Constants.Dashboard.LeftPanel.EditChecklistTemplate.HEAT) + return DBGeneral.select_query(query) + + @staticmethod + def fetchEngByVfName(vfName): + # Fetch one AT&T user ID. + return DBGeneral.select_where("engagement_id", "ice_vf", "name", vfName, 1) + + @staticmethod + def fetchEngManIdByEngUuid(engagement_id): + return DBGeneral.select_where("engagement_manual_id", "ice_engagement", "uuid", engagement_id, 1) + + @staticmethod + def fetchChecklistByName(checklistName): + query = "select uuid from ice_checklist where name='{cl_name}'".format( + cl_name=checklistName) + return DBGeneral.select_query(query) + + @staticmethod + def create_default_heat_teampleate(): + template_query = "INSERT INTO public.ice_checklist_template(uuid, name, category, version, create_time)"\ + "VALUES ('%s', '%s', '%s', '%s', '%s');" % ( + str(uuid4()), 'Editing Heat', 'first category', '1', timezone.now()) + DBGeneral.insert_query(template_query) + template_id = DBGeneral.select_query( + "SELECT uuid FROM public.ice_checklist_template where name = 'Editing Heat'") + # SECTIONS + section1_query = "INSERT INTO public.ice_checklist_section(uuid, name, weight, description, validation_instructions, create_time, template_id) "\ + "VALUES ('%s', '%s', '%s', '%s', '%s','%s', '%s');" % (str(uuid4()), 'External References', + '1', 'section descripyion', 'valid instructions', timezone.now(), template_id) + DBGeneral.insert_query(section1_query) + section1_id = DBGeneral.select_query( + ("""SELECT uuid FROM public.ice_checklist_section where name = 'External References' and template_id = '{s}'""").format(s=template_id)) + section2_query = "INSERT INTO public.ice_checklist_section(uuid, name, weight, description, validation_instructions, create_time, template_id) "\ + "VALUES ('%s', '%s', '%s', '%s', '%s','%s', '%s');" % (str(uuid4()), 'Parameter Specification', + '2', 'section descripyion', 'valid instructions', timezone.now(), template_id) + DBGeneral.insert_query(section2_query) + section2_id = DBGeneral.select_query( + ("""SELECT uuid FROM public.ice_checklist_section where name = 'Parameter Specification' and template_id = '{s}'""").format(s=template_id)) + # Line items + line_item1 = "INSERT INTO public.ice_checklist_line_item(uuid, name, weight, description, line_type, validation_instructions,create_time,section_id, template_id) "\ + "VALUES ('%s', '%s', '%s', '%s', '%s','%s', '%s', '%s', '%s');" % (str(uuid4()), 'Normal references', '1', 'Numeric parameters should include range and/or allowed values.', 'manual', + 'Here are some useful tips for how to validate this item in the most awesome way:<br><br><ul><li>Here is my awesome tip 1</li><li>Here is my awesome tip 2</li><li>Here is my awesome tip 3</li></ul>', timezone.now(), section1_id, template_id) + DBGeneral.insert_query(line_item1) + line_item2 = "INSERT INTO public.ice_checklist_line_item(uuid, name, weight, description, line_type, validation_instructions,create_time, section_id, template_id) "\ + "VALUES ('%s', '%s', '%s', '%s', '%s','%s', '%s', '%s', '%s');" % (str(uuid4()), 'String parameters', '2', 'Numeric parameters should include range and/or allowed values.', 'auto', + 'Here are some useful tips for how to validate this item in the most awesome way:<br><br><ul><li>Here is my awesome tip 1</li><li>Here is my awesome tip 2</li><li>Here is my awesome tip 3</li></ul>', timezone.now(), section2_id, template_id) + DBGeneral.insert_query(line_item2) + line_item3 = "INSERT INTO public.ice_checklist_line_item(uuid, name, weight, description, line_type, validation_instructions,create_time,section_id, template_id) "\ + "VALUES ('%s', '%s', '%s', '%s', '%s','%s', '%s', '%s', '%s');" % (str(uuid4()), 'Numeric parameters', '3', 'Numeric parameters should include range and/or allowed values.', 'manual', + 'Here are some useful tips for how to validate this item in the most awesome way:<br><br><ul><li>Here is my awesome tip 1</li><li>Here is my awesome tip 2</li><li>Here is my awesome tip 3</li></ul>', timezone.now(), section2_id, template_id) + DBGeneral.insert_query(line_item3) + line_item4 = "INSERT INTO public.ice_checklist_line_item(uuid, name, weight, description, line_type, validation_instructions,create_time, section_id, template_id) "\ + "VALUES ('%s', '%s', '%s', '%s', '%s','%s', '%s', '%s', '%s');" % (str(uuid4()), 'VF image', '2', 'Numeric parameters should include range and/or allowed values.', 'auto', + 'Here are some useful tips for how to validate this item in the most awesome way:<br><br><ul><li>Here is my awesome tip 1</li><li>Here is my awesome tip 2</li><li>Here is my awesome tip 3</li></ul>', timezone.now(), section1_id, template_id) + DBGeneral.insert_query(line_item4) + line_item5 = "INSERT INTO public.ice_checklist_line_item(uuid, name, weight, description, line_type, validation_instructions,create_time,section_id, template_id) "\ + "VALUES ('%s', '%s', '%s', '%s', '%s','%s', '%s', '%s', '%s');" % (str(uuid4()), 'Parameters', '1', 'Numeric parameters should include range and/or allowed values.', 'auto', + 'Here are some useful tips for how to validate this item in the most awesome way:<br><br><ul><li>Here is my awesome tip 1</li><li>Here is my awesome tip 2</li><li>Here is my awesome tip 3</li></ul>', timezone.now(), section2_id, template_id) + DBGeneral.insert_query(line_item5) + + @staticmethod + def create_editing_cl_template_if_not_exist(): + template_id = DBGeneral.select_query(("""SELECT uuid FROM public.ice_checklist_template where name = '{s}'""").format( + s=Constants.Dashboard.LeftPanel.EditChecklistTemplate.HEAT)) + if template_id == 'None': + DBChecklist.create_default_heat_teampleate() + session.createTemplatecount = True + + @staticmethod + def state_changed(identify_field, field_value, expected_state): + get_state = str(DBGeneral.select_where( + "state", Constants.DBConstants.IceTables.CHECKLIST, identify_field, field_value, 1)) + counter = 0 + while get_state != expected_state and counter <= Constants.DBConstants.RETRIES_NUMBER: + time.sleep(session.wait_until_time_pause_long) + logger.debug("Checklist state not changed yet , expecting state: %s, current result: %s (attempt %s of %s)" % ( + expected_state, get_state, counter, Constants.DBConstants.RETRIES_NUMBER)) + counter += 1 + get_state = str(DBGeneral.select_where( + "state", Constants.DBConstants.IceTables.CHECKLIST, identify_field, field_value, 1)) + + if get_state == expected_state: + logger.debug("Checklist state was successfully changed into: " + + expected_state + ", and was verified over the DB") + return expected_state + raise Exception( + "Expected checklist state never arrived " + expected_state, get_state) + + @staticmethod + def get_recent_checklist_uuid(name): + required_uuid = DBGeneral.select_where_not_and_order_by_desc( + 'uuid', Constants.DBConstants.IceTables.CHECKLIST, 'name', name, 'state', Constants.ChecklistStates.Archive.TEXT, 'create_time') + return required_uuid diff --git a/services/database/db_cms.py b/services/database/db_cms.py new file mode 100644 index 0000000..3c2b2c6 --- /dev/null +++ b/services/database/db_cms.py @@ -0,0 +1,265 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +import psycopg2 +from wheel.signatures import assertTrue + +from services.constants import Constants +from services.database.db_general import DBGeneral +from services.frontend.base_actions.click import Click +from services.frontend.base_actions.enter import Enter +from services.frontend.base_actions.wait import Wait +from services.frontend.fe_dashboard import FEDashboard +from services.frontend.fe_general import FEGeneral +from services.frontend.fe_user import FEUser +from services.helper import Helper +from services.logging_service import LoggingServiceFactory +from services.session import session + + +logger = LoggingServiceFactory.get_logger() + + +class DBCMS: + + @staticmethod + def insert_query(queryStr): + try: + nativeIceDb = psycopg2.connect( + DBGeneral.return_db_native_connection('cms_db')) + dbConn = nativeIceDb + cur = dbConn.cursor() + logger.debug("Query: " + queryStr) + cur.execute(queryStr) + dbConn.commit() + dbConn.close() + logger.debug("Insert query success!") + # If failed - count the failure and add the error to list of errors. + except: + raise Exception("Couldn't fetch answer using the given query.") + + @staticmethod + def update_query(queryStr): + try: + nativeIceDb = psycopg2.connect( + DBGeneral.return_db_native_connection('cms_db')) + dbConn = nativeIceDb + cur = dbConn.cursor() + logger.debug("Query: " + queryStr) + cur.execute(queryStr) + dbConn.commit() + dbConn.close() + logger.debug("Update query success!") + # If failed - count the failure and add the error to list of errors. + except: + raise Exception("Couldn't fetch answer using the given query.") + + @staticmethod + def select_query(queryStr): + try: + nativeIceDb = psycopg2.connect( + DBGeneral.return_db_native_connection('cms_db')) + dbConn = nativeIceDb + cur = dbConn.cursor() + logger.debug("Query: " + queryStr) + cur.execute(queryStr) + result = str(cur.fetchone()) + if(result.find("',)") != -1): # formatting strings e.g uuid + result = result.partition('\'')[-1].rpartition('\'')[0] + elif(result.find(",)") != -1): # formatting ints e.g id + result = result.partition('(')[-1].rpartition(',')[0] + dbConn.close() + logger.debug("Query result: " + str(result)) + return result + # If failed - count the failure and add the error to list of errors. + except: + raise Exception("Couldn't fetch answer using the given query.") + + @staticmethod + def get_cms_category_id(categoryName): + logger.debug("Get DBCMS category id for name: " + categoryName) + queryStr = "SELECT id FROM public.blog_blogcategory WHERE title = '%s' LIMIT 1;" % ( + categoryName) + logger.debug("Query : " + queryStr) + result = DBCMS.select_query(queryStr) + return result + + @staticmethod + def insert_cms_new_post(title, description, categoryName): + logger.debug("Insert new post : " + title) + queryStr = "INSERT INTO public.blog_blogpost" \ + "(comments_count, keywords_string, rating_count, rating_sum, rating_average, title, slug, _meta_title, description, gen_description, created, updated, status, publish_date, expiry_date, short_url, in_sitemap, content, allow_comments, featured_image, site_id, user_id) "\ + "VALUES (0, '', 0, 0, 0, '%s', '%s-slug', '', '%s', true, current_timestamp - interval '1 day', current_timestamp - interval '2 day', 2, current_timestamp - interval '1 day', NULL, '', true, '<p>%s</p>', true, '', 1, 1);" % ( + title, title, description, description) + logger.debug("Query : " + queryStr) + DBCMS.insert_query(queryStr) + post_id = DBCMS.get_last_added_post_id() + categoryId = DBCMS.get_cms_category_id(categoryName) + DBCMS.add_category_to_post(post_id, categoryId) + return post_id + + @staticmethod + def get_last_added_post_id(): + logger.debug("Get the id of the post inserted") + queryStr = "select MAX(id) FROM public.blog_blogpost;" + logger.debug("Query : " + queryStr) + result = DBCMS.select_query(queryStr) + return result + + @staticmethod + def update_days(xdays, title): + logger.debug("Get the id of the post inserted") +# queryStr = "select MAX(id) FROM public.blog_blogpost;" + queryStr = "UPDATE public.blog_blogpost SET created=current_timestamp - interval '%s day' WHERE title='%s';" % ( + xdays, title) + logger.debug("Query : " + queryStr) + result = DBCMS.update_query(queryStr) + return result + + @staticmethod + def add_category_to_post(postId, categoryId): + logger.debug("bind category into inserted post: " + postId) + queryStr = "INSERT INTO public.blog_blogpost_categories(blogpost_id, blogcategory_id) VALUES (%s, %s);" % ( + postId, categoryId) + logger.debug("Query : " + queryStr) + DBCMS.insert_query(queryStr) + + @staticmethod + def get_documentation_page_id(): + logger.debug("Retrive id of documentation page: ") + queryStr = "SELECT id FROM public.pages_page WHERE title = 'Documentation' LIMIT 1;" + logger.debug("Query : " + queryStr) + result = DBCMS.select_query(queryStr) + return result + + @staticmethod + def get_last_inserted_page_id(): + logger.debug("Retrive id of last page inserted: ") + queryStr = "select MAX(id) FROM public.pages_page;" + logger.debug("Query : " + queryStr) + result = DBCMS.select_query(queryStr) + return result + + @staticmethod + def delete_old_tips_of_the_day(): + logger.debug("Delete all posts ") + queryStr = "DELETE FROM public.blog_blogpost_categories WHERE id>0;" + logger.debug("Query : " + queryStr) + DBCMS.insert_query(queryStr) + queryStr = "DELETE FROM public.blog_blogpost WHERE id>0;;" + logger.debug("Query : " + queryStr) + DBCMS.insert_query(queryStr) + + @staticmethod + def insert_page(title, content, parent_id=None): + logger.debug("Retrive id of documentation page: ") + if parent_id is None: + parent_id = DBCMS.get_documentation_page_id() + queryStr = "INSERT INTO public.pages_page(" \ + "keywords_string, title, slug, _meta_title, description, gen_description, created, updated, status, publish_date, expiry_date, short_url, in_sitemap, _order, in_menus, titles, content_model, login_required, parent_id, site_id)" \ + "VALUES ('', '%s', '%s-slug', '', '%s', true, current_timestamp - interval '1 day', current_timestamp - interval '1 day', 2, current_timestamp - interval '1 day', NULL, '', true, 0, '1,2,3', '%s', 'richtextpage', true, %s, 1);" % ( + title, title, content, title, parent_id) + logger.debug("Query : " + queryStr) + DBCMS.insert_query(queryStr) + + createdPageId = DBCMS.get_last_inserted_page_id() + logger.debug( + "Bind the page with the rich text content related to this page") + queryStr = "INSERT INTO public.pages_richtextpage(page_ptr_id, content) VALUES (%s, '<p>%s</p>');" % ( + createdPageId, content) + logger.debug("Query : " + queryStr) + DBCMS.insert_query(queryStr) + return createdPageId + + @staticmethod + def create_faq(): + title = "title_FAQ" + Helper.rand_string("randomString") + description = "description_FAQ_" + Helper.rand_string("randomString") + DBCMS.delete_old_tips_of_the_day() + postId = DBCMS.insert_cms_new_post(title, description, "FAQ") + assertTrue(len(postId) > 0 and not None) + return title, description + + @staticmethod + def create_news(): + title = "title_News" + Helper.rand_string("randomString") + description = "description_News" + Helper.rand_string("randomString") + postId = DBCMS.insert_cms_new_post(title, description, "News") + assertTrue(len(postId) > 0 and not None) + return title, description + + @staticmethod + def create_announcement(): + title = "title_Announcement_" + Helper.rand_string("randomString") + description = "description_Announcement_" + \ + Helper.rand_string("randomString") + postId = DBCMS.insert_cms_new_post(title, description, "Announcement") + assertTrue(len(postId) > 0 and not None) + return title, description + + @staticmethod + def create_page(parent_id=None): + title = "title_Of_Page_" + Helper.rand_string("randomString") + description = "description_Of_Page_" + \ + Helper.rand_string("randomString") + createdPageId = DBCMS.insert_page(title, description) + assertTrue(len(createdPageId) > 0 and not None) + return title, description + + @staticmethod + def update_X_days_back_post(title, xdays): + logger.debug("Get the id of the post inserted") + queryStr = "UPDATE blog_blogpost SET created = current_timestamp - interval '%s day', publish_date=current_timestamp - interval '%s day' WHERE title= '%s' ;" % ( + xdays, xdays, title) + logger.debug("Query : " + queryStr) + DBCMS.update_query(queryStr) + + @staticmethod + def create_announcements(x): + listOfTitleAnDescriptions = [] + for _ in range(x): + # print x ->str + title = "title_Announcement_" + Helper.rand_string("randomString") + description = "description_Announcement_" + \ + Helper.rand_string("randomString") + postId = DBCMS.insert_cms_new_post( + title, description, "Announcement") + assertTrue(len(postId) > 0 and not None) + xList = [title, description] + listOfTitleAnDescriptions.append(xList) + return listOfTitleAnDescriptions diff --git a/services/database/db_general.py b/services/database/db_general.py new file mode 100755 index 0000000..c850d3a --- /dev/null +++ b/services/database/db_general.py @@ -0,0 +1,416 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +from datetime import datetime +import sqlite3 + +from django.conf import settings +from django.db import transaction +import psycopg2 + +from services.logging_service import LoggingServiceFactory + + +logger = LoggingServiceFactory.get_logger() + +class DBGeneral: + + @staticmethod + # desigredDB: Use 'default' for CI General and 'em_db' for EM General + # (according to settings.DATABASES). + def return_db_native_connection(desigredDB): + dbConnectionStr = "dbname='" + str(settings.SINGLETONE_DB[desigredDB]['NAME']) + \ + "' user='" + str(settings.SINGLETONE_DB[desigredDB]['USER']) + \ + "' host='" + str(settings.SINGLETONE_DB[desigredDB]['HOST']) + \ + "' password='" + str(settings.SINGLETONE_DB[desigredDB]['PASSWORD']) + \ + "' port='" + \ + str(settings.SINGLETONE_DB[desigredDB]['PORT']) + "'" + return dbConnectionStr + + @staticmethod + def insert_results(testType, testFeature, testResult, testName, testDuration, notes=" "): + try: + if settings.DATABASE_TYPE == 'sqlite': + dbfile = str(settings.DATABASES['default']['TEST_NAME']) + dbConn = sqlite3.connect(dbfile) + cur = dbConn.cursor() + else: + # Connect to General 'default'. + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection("default")) + dbConn = dbConn + cur = dbConn.cursor() + except Exception as e: + errorMsg = "Failed to create connection to General." + str(e) + raise Exception(errorMsg) + try: # Create INSERT query. + if settings.DATABASE_TYPE == 'sqlite': + query_str = 'INSERT INTO ice_test_results (testType, testFeature, testResult, testName, notes,'\ + 'create_time, build_id, duration) VALUES (?, ?, ?, ?, ?, ?, ?, ?);' + else: + query_str = 'INSERT INTO ice_test_results ("testType", "testFeature", "testResult", "testName", notes,'\ + 'create_time, build_id, duration) VALUES (%s, %s, %s, %s, %s, %s, %s, %s);' + cur.execute(query_str, (testType, testFeature, testResult, testName, notes, str(datetime.now()), + settings.ICE_BUILD_REPORT_NUM, testDuration)) + dbConn.commit() + logger.debug("Test result in DB - " + testResult) + except Exception as e: + logger.error(e) + errorMsg = "Failed to insert results to DB." + str(e) + raise Exception(errorMsg) + dbConn.close() + + @staticmethod + def select_query(queryStr, return_type="str", fetch_num=1): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = dbConn + cur = dbConn.cursor() + logger.debug("Query: " + queryStr) + cur.execute(queryStr) + if return_type == "str": + if fetch_num == 1: + result = str(cur.fetchone()) + else: + result = str(cur.fetchall()) + if result != 'None': + # formatting strings e.g uuid + if(result.find("',)") != -1): + result = result.partition('\'')[-1].rpartition('\'')[0] + elif(result.find(",)") != -1): # formatting ints e.g id + result = result.partition('(')[-1].rpartition(',')[0] + if return_type == "list": + if fetch_num == 1: + result = list(cur.fetchone()) + else: + result = [item[0] for item in cur.fetchall()] + dbConn.close() + logger.debug("Query result: " + str(result)) + return result + except: + raise Exception("Couldn't fetch answer using the given query.") + + @staticmethod + def insert_query(queryStr): + try: + nativeIceDb = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = nativeIceDb + cur = dbConn.cursor() + logger.debug("Query: " + queryStr) + cur.execute(queryStr) + dbConn.commit() + dbConn.close() + logger.debug("Insert query success!") + # If failed - count the failure and add the error to list of errors. + except Exception as e: + logger.error(e) + transaction.rollback() + raise Exception("Couldn't fetch answer using the given query.") + + @staticmethod + def update_query(queryStr): + try: + nativeIceDb = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = nativeIceDb + cur = dbConn.cursor() + logger.debug("Query: " + queryStr) + cur.execute(queryStr) + dbConn.commit() + dbConn.close() + logger.debug("Update query success!") + # If failed - count the failure and add the error to list of errors. + except Exception as e: + logger.error(e) + transaction.rollback() + raise Exception("Couldn't fetch answer using the given query.") + + @staticmethod + def select_where_email(queryColumnName, queryTableName, email): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = dbConn + cur = dbConn.cursor() + queryStr = "select %s from %s WHERE Email = '%s';" % ( + queryColumnName, queryTableName, email) + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + result = str(cur.fetchone()) + if(result.find("',)") != -1): # formatting strings e.g uuid + result = result.partition('\'')[-1].rpartition('\'')[0] + elif(result.find(",)") != -1): # formatting ints e.g id + result = result.partition('(')[-1].rpartition(',')[0] + dbConn.close() + logger.debug("Query result: " + str(result)) + return result + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "select_where_email FAILED " + raise Exception(errorMsg, "select_where_email") + raise + + @staticmethod + def select_from(queryColumnName, queryTableName, fetchNum): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + cur = dbConn.cursor() + queryStr = "select %s from %s;" % (queryColumnName, queryTableName) + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + if (fetchNum == 0): + result = str(cur.fetchall()) + elif (fetchNum == 1): + result = str(cur.fetchone()) + if(result.find("',)") != -1): # formatting strings e.g uuid + result = result.partition('\'')[-1].rpartition('\'')[0] + elif(result.find(",)") != -1): # formatting ints e.g id + result = result.partition('(')[-1].rpartition(',')[0] + dbConn.close() + logger.debug("Query result: " + str(result)) + return result + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "select_from FAILED " + str(e) + raise Exception(errorMsg, "select_from") + + @staticmethod + def select_where(queryColumnName, queryTableName, whereParametrType, whereParametrValue, fetchNum): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + cur = dbConn.cursor() + queryStr = "select %s from %s Where %s = '%s';" % ( + queryColumnName, queryTableName, whereParametrType, whereParametrValue) + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + if (fetchNum == 0): + result = list(cur.fetchall()) + elif (fetchNum == 1): + result = str(cur.fetchone()) + if(result.find("',)") != -1): # formatting strings e.g uuid + result = result.partition('\'')[-1].rpartition('\'')[0] + elif(result.find(",)") != -1): # formatting ints e.g id + result = result.partition('(')[-1].rpartition(',')[0] + dbConn.close() + logger.debug("Query result: " + str(result)) + return result + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "select_where FAILED " + raise Exception(errorMsg, "select_where") + + @staticmethod + def select_where_order_by_desc(queryColumnName, queryTableName, whereParametrType, whereParametrValue, order_by): + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + cur = dbConn.cursor() + queryStr = "select %s from %s Where %s = '%s' order by %s desc limit 1;" \ + % (queryColumnName, queryTableName, whereParametrType, whereParametrValue, order_by) + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + result = str(cur.fetchall()) + result = DBGeneral.list_format(result) + dbConn.close() + return result + + @staticmethod + def select_where_dict(queryColumnName, queryTableName, whereParametrType): + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + cur = dbConn.cursor() + x = "" + count = 0 + for key, val in whereParametrType.items(): + x += "%s='%s'" % (key, val) + if len(whereParametrType.items()) - count > 1: + x += ' and ' + count += 1 + queryStr = "select %s from %s Where %s;" \ + % (queryColumnName, queryTableName, x) + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + result = str(cur.fetchall()) + result = DBGeneral.list_format(result) + dbConn.close() + return result + + @staticmethod + def select_where_not_and_order_by_desc(queryColumnName, queryTableName, whereParametrType, + whereParametrValue, parametrTypeAnd, parametrAnd, order_by): + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + cur = dbConn.cursor() + queryStr = "select %s from %s Where %s = '%s' and %s != '%s' order by %s desc limit 1;" \ + % (queryColumnName, queryTableName, whereParametrType, whereParametrValue, + parametrTypeAnd, parametrAnd, order_by) + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + result = str(cur.fetchall()) + result = DBGeneral.list_format(result) + dbConn.close() + return result + + @staticmethod + def select_where_and(queryColumnName, queryTableName, whereParametrType, whereParametrValue, + parametrTypeAnd, parametrAnd, fetchNum): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = dbConn + cur = dbConn.cursor() + queryStr = "select %s from %s Where %s = '%s' and %s = '%s';" % ( + queryColumnName, queryTableName, whereParametrType, whereParametrValue, parametrTypeAnd, parametrAnd) + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + if (fetchNum == 0): + result = str(cur.fetchall()) + result = DBGeneral.list_format(result) + elif (fetchNum == 1): + result = str(cur.fetchone()) + if(result.find("',)") != -1): # formatting strings e.g uuid + result = result.partition('\'')[-1].rpartition('\'')[0] + elif(result.find(",)") != -1): # formatting ints e.g id + result = result.partition('(')[-1].rpartition(',')[0] + dbConn.close() + logger.debug("Query result: " + str(result)) + return result + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "select_where_and FAILED " + raise Exception(errorMsg, "select_where_and") + + @staticmethod + def select_where_is_bigger(queryColumnName, queryTableName, whereParametrType, whereParametrValue, parametrTypeAnd, parametrAnd, fetchNum): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = dbConn + cur = dbConn.cursor() + queryStr = "select %s from %s Where %s = '%s' and %s > %s;" % ( + queryColumnName, queryTableName, whereParametrType, whereParametrValue, parametrTypeAnd, parametrAnd) + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + if (fetchNum == 0): + result = cur.fetchall() + elif (fetchNum == 1): + result = cur.fetchone() + if(result.find("',)") != -1): # formatting strings e.g uuid + result = result.partition('\'')[-1].rpartition('\'')[0] + elif(result.find(",)") != -1): # formatting ints e.g id + result = result.partition('(')[-1].rpartition(',')[0] + dbConn.close() + return result + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "select_where_is_bigger FAILED " + raise Exception(errorMsg, "select_where_is_bigger") + + @staticmethod + def update_where(queryTableName, setParametrType, setparametrValue, whereParametrType, whereParametrValue): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = dbConn + cur = dbConn.cursor() + queryStr = "UPDATE %s SET %s = '%s' Where %s = '%s';" % ( + queryTableName, setParametrType, setparametrValue, whereParametrType, whereParametrValue) + cur.execute(queryStr) + dbConn.commit() + logger.debug("Query : " + queryStr) + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "Could not Update User" + logger.debug(e) + raise Exception(errorMsg, "Update") + finally: + dbConn.close() + + @staticmethod + def update_by_query(queryStr): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = dbConn + cur = dbConn.cursor() + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + dbConn.commit() + dbConn.close() + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "Could not Update User" + raise Exception(errorMsg, "Update") + + @staticmethod + def update_where_and(queryTableName, setParametrType, parametrValue, changeToValue, whereParametrType, setParametrType2, setParametrValue2, whereParametrType2, whereParametrValue2): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = dbConn + cur = dbConn.cursor() + queryStr = "UPDATE %s SET %s = '%s', %s = '%s' Where %s = '%s' and %s = '%s';" % ( + queryTableName, setParametrType, changeToValue, setParametrType2, setParametrValue2, whereParametrType, parametrValue, whereParametrType2, whereParametrValue2) + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + dbConn.commit() + dbConn.close() + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "Could not Update User" + raise Exception(errorMsg, "Update") + + @staticmethod + def list_format(un_listed): + un_listed = un_listed[1:-1] + un_listed = un_listed.replace("',), ('", "|||") + un_listed = un_listed.replace("(u'", "") # Format list + un_listed = un_listed[1:-1].replace("('", "") # Format list + un_listed = un_listed.replace("',)", "") # Format list + listed = un_listed[1:-2].split("|||") + return listed + + @staticmethod + def get_vendors_list(): + # Select approved vendors from db. + vendors_list = DBGeneral.select_where( + "name", "ice_vendor", "public", "TRUE", 0) + return vendors_list diff --git a/services/database/db_user.py b/services/database/db_user.py new file mode 100644 index 0000000..d347dd2 --- /dev/null +++ b/services/database/db_user.py @@ -0,0 +1,417 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +import time + +from django.conf import settings +import psycopg2 + +from services.constants import Constants +from services.database.db_bridge import DBBridge +from services.database.db_general import DBGeneral +from services.database.db_virtual_function import DBVirtualFunction +from services.frontend.base_actions.wait import Wait +from services.logging_service import LoggingServiceFactory +from services.session import session + + +logger = LoggingServiceFactory.get_logger() + +class DBUser: + + @staticmethod + def get_activation_url(email): + # Fetch one user ID. + uuid = DBUser.select_user_uuid(email) + # Fetch one user ID. + index = DBGeneral.select_where_email("id", "auth_user", email) + activation_token = DBGeneral.select_where( + "activation_token", "ice_custom_user", "user_ptr_id", index, 1) + # / activate /:userID /:token + activationUrl = settings.ICE_PORTAL_URL + '/#/activate/' + \ + str(uuid) + '/' + str(activation_token) + logger.debug("activationUrl :" + activationUrl) + return activationUrl + + @staticmethod + def get_contact_signup_url(invite_token, uuid, email, fullName, phoneNum, companyName): + companyId = DBGeneral.select_where( + "uuid", "ice_vendor", "name", companyName, 1) + signUpURLforContact = settings.ICE_PORTAL_URL + "#/signUp?invitation=" + invite_token + \ + "&email=" + email + "&full_name=" + fullName + \ + "&phone_number=" + phoneNum + "&company=" + companyId + logger.debug("SignUpURLforContact :" + signUpURLforContact) + return signUpURLforContact + + @staticmethod + def select_invitation_token(queryColumnName, queryTableName, whereParametrType, whereParametrValue, email, fetchNum): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = dbConn + cur = dbConn.cursor() + queryStr = "select %s from %s Where %s = '%s' and email = '%s' ;" % ( + queryColumnName, queryTableName, whereParametrType, whereParametrValue, email) + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + if (fetchNum == 0): + result = str(cur.fetchall()) + elif (fetchNum == 1): + result = str(cur.fetchone()) + if(result.find("',)") != -1): # formatting strings e.g uuid + result = result.partition('\'')[-1].rpartition('\'')[0] + elif(result.find(",)") != -1): # formatting ints e.g id + result = result.partition('(')[-1].rpartition(',')[0] + dbConn.close() + if result == None: + errorMsg = "select_where_pr_state FAILED " + logger.error(errorMsg) + raise + logger.debug("Query result: " + str(result)) + return result + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "select_where FAILED " + raise Exception(errorMsg, "select_where") + + @staticmethod + def get_el_name(vfName): + try: + # Fetch one AT&T user ID. + engagement_id = DBVirtualFunction.select_eng_uuid(vfName) + engagement_manual_id = DBGeneral.select_where( + "engagement_manual_id", "ice_engagement", "uuid", engagement_id, 1) + reviewer_id = DBGeneral.select_where( + "reviewer_id", "ice_engagement", "engagement_manual_id", engagement_manual_id, 1) + engLeadFullName = DBGeneral.select_where_and( + "full_name", "ice_user_profile", "id", reviewer_id, "role_id", "2", 1) + return engLeadFullName + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "get_el_name FAILED " + raise Exception(errorMsg, "get_el_name") + + @staticmethod + def get_email_by_full_name(fullname): + # try: + query_str = "select email from ice_user_profile where full_name = '%s';" % ( + fullname) + user_email = DBGeneral.select_query(query_str) + return user_email +# except: # If failed - count the failure and add the error to list of errors. +# errorMsg = "get_email_by_full_name FAILED " +# raise Exception(errorMsg, "get_el_name") + + @staticmethod + def select_recent_vf_of_user(user_uuid, fetchNum): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = dbConn + cur = dbConn.cursor() + queryStr = "SELECT vf_id FROM public.ice_recent_engagement where user_uuid = '%s' order by last_update desc limit 20;" % ( + user_uuid) + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + if (fetchNum == 0): + result = str(cur.fetchall()) + elif (fetchNum == 1): + result = str(cur.fetchone()) + if(result.find("',)") != -1): # formatting strings e.g uuid + result = result.partition('\'')[-1].rpartition('\'')[0] + elif(result.find(",)") != -1): # formatting ints e.g id + result = result.partition('(')[-1].rpartition(',')[0] + dbConn.close() + logger.debug("Query result: " + str(result)) + return result + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "select_where FAILED " + raise Exception(errorMsg, "select_where") + + @staticmethod + def select_el_email(vfName): + try: + # Fetch one AT&T user ID. + engagement_id = DBVirtualFunction.select_eng_uuid(vfName) + engagement_manual_id = DBGeneral.select_where( + "engagement_manual_id", "ice_engagement", "uuid", engagement_id, 1) + reviewer_id = DBGeneral.select_where( + "reviewer_id", "ice_engagement", "engagement_manual_id", engagement_manual_id, 1) + engLeadEmail = DBGeneral.select_where_and( + "email", "ice_user_profile", "id", reviewer_id, "role_id", "2", 1) + return engLeadEmail + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "select_el_email FAILED " + raise Exception(errorMsg, "select_el_email") + + @staticmethod + def select_user_native_id(email): + try: + # Fetch one AT&T user ID. + engLeadId = DBUser.select_user_profile_property(email, "id") + return engLeadId + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "select_user_native_id FAILED " + raise Exception(errorMsg, "select_user_native_id") + + @staticmethod + def select_personal_next_step(email): + user_id = DBUser.select_user_native_id(email) + return DBGeneral.select_where("uuid", "ice_next_step", "owner_id", user_id, 1) + + @staticmethod + def select_pr_email(vfName): + try: + # Fetch one AT&T user ID. + engagement_id = DBVirtualFunction.select_eng_uuid(vfName) + engagement_manual_id = DBGeneral.select_where( + "engagement_manual_id", "ice_engagement", "uuid", engagement_id, 1) + reviewer_id = DBGeneral.select_where( + "peer_reviewer_id", "ice_engagement", "engagement_manual_id", engagement_manual_id, 1) + engLeadEmail = DBGeneral.select_where( + "email", "ice_user_profile", "id", reviewer_id, 1) + return engLeadEmail + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "select_el_email FAILED " + raise Exception(errorMsg, "select_el_email") + + @staticmethod + def get_notification_id_by_email(userEmail): + uuid = DBGeneral.select_where_email( + "id", "ice_user_profile", userEmail) + notifIDs = DBGeneral.select_where( + "uuid", "ice_notification", "user_id", uuid, 0) + return notifIDs + + @staticmethod + def get_not_seen_notifications_number_by_email(user_email, is_negative=False): + user_id = DBGeneral.select_where_email( + "id", Constants.DBConstants.IceTables.USER_PROFILE, user_email) + notifications_number = DBGeneral.select_where_and( + Constants.DBConstants.Queries.COUNT, Constants.DBConstants.IceTables.NOTIFICATION, "user_id", user_id, "is_read", "False", 1) + if is_negative: + counter = 0 + while notifications_number != "0" and counter <= Constants.Dashboard.Avatar.Notifications.Count.RETRIES_NUMBER: + notifications_number = DBGeneral.select_where_and( + Constants.DBConstants.Queries.COUNT, Constants.DBConstants.IceTables.NOTIFICATION, "user_id", user_id, "is_read", "False", 1) + time.sleep(1) + counter += 1 + return notifications_number + + @staticmethod + def get_eng_lead_email_per_enguuid(enguuid): + reviewer_id = DBGeneral.select_where( + "reviewer_id", Constants.DBConstants.IceTables.ENGAGEMENT, "uuid", enguuid, 1) + engLeadEmail = DBGeneral.select_where( + "email", Constants.DBConstants.IceTables.USER_PROFILE, "id", reviewer_id, 1) + return engLeadEmail + + @staticmethod + def select_all_user_engagements(engLeadID): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = dbConn + cur = dbConn.cursor() + queryStr = "select COUNT(*) from ice_engagement_engagement_team Where iceuserprofile_id = %s and (select engagement_stage from public.ice_engagement where uuid = engagement_id LIMIT 1) != 'Archived';" % ( + engLeadID) + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + result = cur.fetchall() + dbConn.close() + logger.debug("Query result: " + str(result)) + logger.debug(result[0][0]) + return result[0][0] + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "select_user_engagements_by_stage FAILED " + raise Exception(errorMsg, "select_user_engagements_by_stage") + + @staticmethod + def select_user_engagements_by_stage(stage, engLeadID): + try: + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection('em_db')) + dbConn = dbConn + cur = dbConn.cursor() + queryStr = "select count(*) from ice_engagement INNER JOIN ice_engagement_engagement_team ON ice_engagement_engagement_team.engagement_id= ice_engagement.uuid Where (ice_engagement.engagement_stage = '%s') and (ice_engagement_engagement_team.iceuserprofile_id = %s );" % ( + stage, engLeadID) + logger.debug("Query : " + queryStr) + cur.execute(queryStr) + result = cur.fetchall() + dbConn.close() + logger.debug("Query result: " + str(result)) + logger.debug(result[0][0]) + return result[0][0] + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "select_user_engagements_by_stage FAILED " + raise Exception(errorMsg, "select_user_engagements_by_stage") + + @staticmethod + def set_new_temp_password(email): + encodePass = DBGeneral.select_where_email( + "password", "auth_user", Constants.Users.Admin.EMAIL) + # Fetch one user ID. + index = DBGeneral.select_where_email("id", "auth_user", email) + DBGeneral.update_where( + "ice_custom_user", "temp_password", encodePass, "user_ptr_id", index) + + @staticmethod + def set_password_to_default(email): + encodePass = DBGeneral.select_where_email( + "password", "auth_user", Constants.Users.Admin.EMAIL) + DBGeneral.update_where( + "auth_user", "password", encodePass, "email", email) + + @staticmethod + def select_el_not_in_engagement(el_name, pr_name): + query_str = "select full_name from ice_user_profile where role_id = 2 and full_name != '%s' and full_name != '%s';" % ( + el_name, pr_name) + new_user = DBGeneral.select_query(query_str) + if new_user == 'None': + new_user = DBUser.update_to_el_not_in_engagement() + return new_user + + @staticmethod + def select_user_uuid(email): + user_uuid = DBUser.select_user_profile_property(email, "uuid") + return user_uuid + + @staticmethod + def select_access_key(email): + access_key = DBUser.select_user_profile_property(email, "rgwa_access_key") + return access_key + + @staticmethod + def select_secret_key(email): + secret_key = DBUser.select_user_profile_property(email, "rgwa_secret_key") + return secret_key + + @staticmethod + def update_to_el_not_in_engagement(): + query_str = "select uuid from ice_user_profile where role_id = 1 ;" + user_uuid = DBGeneral.select_query(query_str) + updatequery = "UPDATE ice_user_profile SET role_id=2 ,full_name = 'el_for_test' WHERE uuid = '%s' ;" % ( + user_uuid) + DBGeneral.update_query(updatequery) + updatequery = "UPDATE ice_user_profile SET role_id=2 WHERE full_name = '%s' ;" % ( + 'el_for_test') + DBGeneral.update_query(updatequery) + return 'el_for_test' + + @staticmethod + def rollback_for_el_not_in_engagement(): + query_str = "select uuid from ice_user_profile where full_name = 'el_for_test';" + user_uuid = DBGeneral.select_query(query_str) + fullName = DBBridge.helper_rand_string("randomString") + updatequery = "UPDATE ice_user_profile SET role_id=1,full_name = '%s' WHERE uuid = '%s' ;" % ( + fullName, user_uuid) + DBGeneral.update_query(updatequery) + + @staticmethod + def set_engagement_peer_reviewer(engagement_uuid, email): + user_uuid = DBUser.select_user_uuid(email) + update_query = "UPDATE ice_user_profile SET role_id=2 WHERE uuid = '%s';" % user_uuid + DBGeneral.update_query(update_query) + + user_id = DBGeneral.select_query( + "SELECT id FROM ice_user_profile WHERE uuid = '%s';" % user_uuid) + update_query = "UPDATE ice_engagement SET peer_reviewer_id=%s WHERE uuid = '%s';" % ( + user_id, engagement_uuid) + DBGeneral.update_query(update_query) + + @staticmethod + def select_user_profile_property(user_email, property_name): + return DBGeneral.select_where(property_name, "ice_user_profile", "email", user_email, 1) + + @staticmethod + def validate_user_profile_settings_in_db(user_email, checked): + Wait.page_has_loaded() + regular_email_updates = DBUser.select_user_profile_property( + user_email, 'regular_email_updates') + DBBridge.helper_internal_assert(regular_email_updates, checked) + email_updates_on_every_notification = \ + DBUser.select_user_profile_property( + user_email, 'email_updates_on_every_notification') + DBBridge.helper_internal_assert( + email_updates_on_every_notification, checked) + email_updates_daily_digest = DBUser.select_user_profile_property( + user_email, 'email_updates_daily_digest') + DBBridge.helper_internal_assert( + email_updates_daily_digest, not checked) + + @staticmethod + def retrieve_admin_ssh_from_db(): + ssh_key = DBGeneral.select_where( + 'ssh_public_key', Constants.DBConstants.IceTables.USER_PROFILE, + 'email', Constants.Users.Admin.EMAIL, 1) + return ssh_key + + @staticmethod + def get_access_key(user_uuid): + counter = 0 + access_key = DBGeneral.select_where( + "rgwa_access_key", Constants.DBConstants.IceTables.USER_PROFILE, "uuid", user_uuid, 1) + while access_key == "None" and counter <= Constants.RGWAConstants.RETRIES_NUMBER: + time.sleep(session.wait_until_time_pause) + logger.debug( + "rgwa_access_key are not ready yet, trying again (%s of 20)" % counter) + access_key = DBGeneral.select_where( + "rgwa_access_key", Constants.DBConstants.IceTables.USER_PROFILE, "uuid", user_uuid, 1) + counter += 1 + return access_key + + @staticmethod + def get_access_secret(user_uuid): + counter = 0 + access_secret = DBGeneral.select_where( + "rgwa_secret_key", Constants.DBConstants.IceTables.USER_PROFILE, "uuid", user_uuid, 1) + while access_secret == "None" and counter <= Constants.RGWAConstants.RETRIES_NUMBER: + time.sleep(session.wait_until_time_pause) + logger.debug( + "rgwa_secret_key are not ready yet, trying again (%s of 100)" % counter) + access_secret = DBGeneral.select_where( + "rgwa_secret_key", Constants.DBConstants.IceTables.USER_PROFILE, "uuid", user_uuid, 1) + + counter += 1 + return access_secret diff --git a/services/database/db_virtual_function.py b/services/database/db_virtual_function.py new file mode 100644 index 0000000..143bca2 --- /dev/null +++ b/services/database/db_virtual_function.py @@ -0,0 +1,227 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +import uuid + +from django.conf import settings +import psycopg2 + +from services.constants import Constants +from services.database.db_bridge import DBBridge +from services.database.db_general import DBGeneral +from services.logging_service import LoggingServiceFactory + + +logger = LoggingServiceFactory.get_logger() + +class DBVirtualFunction: + + @staticmethod + def insert_ecomp_release(uuid, name, ui_visibility="TRUE"): + try: + queryTableName = "ice_ecomp_release" + # Connect to General 'default'. + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection("em_db")) + dbConn = dbConn + cur = dbConn.cursor() + logger.debug("DATABASE_TYPE: " + settings.DATABASE_TYPE) + except Exception as e: + errorMsg = "Failed to create connection to General: " + str(e) + raise Exception(errorMsg) + try: + logger.debug("DATABASE_TYPE: " + settings.DATABASE_TYPE) + # Create INSERT query. + queryStr = "INSERT INTO %s (""uuid, name, weight, ui_visibility"") VALUES ('%s', '%s', '%s', '%s');" % ( + queryTableName, uuid, name, 0, ui_visibility) + logger.debug("Query: " + queryStr) + cur.execute(queryStr) # Execute query. + dbConn.commit() + logger.debug("Test results are in General now.") + except Exception as e: + errorMsg = "Failed to insert ECOMP release to General:" + str(e) + raise Exception(errorMsg) + dbConn.close() + + @staticmethod + def delete_ecomp_release(uuid, name): + try: + queryTableName = "ice_ecomp_release" + # Connect to General 'default'. + dbConn = psycopg2.connect( + DBGeneral.return_db_native_connection("em_db")) + dbConn = dbConn + cur = dbConn.cursor() + except Exception as e: + errorMsg = "Failed to create connection to DBGeneral.because :" + \ + str(e) + raise Exception(errorMsg) + try: + # Create INSERT query. + queryStr = "DELETE FROM %s WHERE uuid = '%s';" % ( + queryTableName, uuid) + logger.debug("Query: " + queryStr) + cur.execute(queryStr) # Execute query. + dbConn.commit() + logger.debug("Test results are in General now.") + except Exception as e: + errorMsg = "Failed to delete ECOMP release from General . because :" + \ + str(e) + raise Exception(errorMsg) + raise + dbConn.close() + + @staticmethod + def select_next_steps_ids(engagement_uuid): + ice_next_steps = DBGeneral.select_where( + "uuid", "ice_next_step", "engagement_id", engagement_uuid, 0) + return ice_next_steps + + @staticmethod + def select_next_steps_uuids_by_stage(engagement_uuid, engagement_stage): + query = "SELECT uuid FROM %s WHERE engagement_id='%s' AND engagement_stage='%s' ORDER BY position;" % ( + Constants.DBConstants.IceTables.NEXT_STEP, engagement_uuid, engagement_stage) + return DBGeneral.select_query(query, "list", 0) + + @staticmethod + def update_next_step_position(next_step_uuid, new_index): + DBGeneral.update_where( + "ice_next_step", "position", new_index, "uuid", next_step_uuid) + + @staticmethod + def select_next_step_description(next_step_uuid): + return DBGeneral.select_where("description", "ice_next_step", "uuid", next_step_uuid, 1) + + @staticmethod + def select_eng_uuid(vf_name): + return DBGeneral.select_where("engagement_id", "ice_vf", "name", vf_name, 1) + + @staticmethod + def select_engagment_uuid_by_vf_name(vfName): + engagement_id = DBGeneral.select_where( + "engagement_id", "ice_vf", "name", vfName, 1) + engagement_manual_id = DBGeneral.select_where( + "engagement_manual_id", "ice_engagement", "uuid", engagement_id, 1) + enguuid = DBGeneral.select_where( + "uuid", "ice_engagement", "engagement_manual_id", engagement_manual_id, 1) + return enguuid + + @staticmethod + def select_vf_version_by_vf_name(vfName): + queryStr = "SELECT version FROM ice_vf WHERE name= '%s';" % vfName + version_name = str(DBGeneral.select_query(queryStr)) + return version_name + + @staticmethod + def select_vf_name_by_vf_version(version_name): + queryofname = "SELECT name FROM ice_vf WHERE version= '%s';" % version_name + vfNameDb = str(DBGeneral.select_query(queryofname)) + return vfNameDb + + @staticmethod + def return_expected_steps(engagement_uuid, stage, user_email): + steps_uuids = DBVirtualFunction.select_next_steps_uuids_by_stage( + engagement_uuid, stage) + personal_step_uuid = DBBridge.select_personal_next_step(user_email) + DBVirtualFunction.update_next_step_position(personal_step_uuid, 1) + steps_uuids.insert(0, personal_step_uuid) + return steps_uuids + + @staticmethod + def get_engagement(): + """Use this function instead of creating a new engagement where no need to""" + queryStr = "SELECT DISTINCT ice_engagement.uuid, engagement_manual_id, ice_vf.name, ice_user_profile.full_name, \ + ice_user_profile.email, reviewer_table.full_name, reviewer_table.email, \ + ice_deployment_target.version, ice_ecomp_release.name \ + FROM ice_engagement LEFT JOIN ice_vf ON engagement_id = ice_engagement.uuid \ + LEFT JOIN ice_user_profile reviewer_table ON reviewer_table.id = ice_engagement.reviewer_id \ + LEFT JOIN ice_user_profile ON ice_user_profile.id = ice_engagement.peer_reviewer_id \ + LEFT JOIN ice_deployment_target ON ice_deployment_target.uuid = ice_vf.deployment_target_id \ + LEFT JOIN ice_ecomp_release ON ice_ecomp_release.uuid = ice_vf.ecomp_release_id \ + WHERE ice_user_profile.id IS NOT NULL LIMIT 1;" + list_of_values = DBGeneral.select_query(queryStr, return_type="list") + list_of_keys = ["engagement_uuid", "engagement_manual_id", "vfName", "pr_name", + "pr_email", "el_name", "el_email", "target_aic", "ecomp_release"] + return dict(zip(list_of_keys, list_of_values)) + + @staticmethod + def insert_aic_version(ui_visibility="TRUE"): + new_aic_version = { + "uuid": str(uuid.uuid4()), "name": "AIC", "version": DBBridge.helper_rand_string("randomNumber", 2), "ui_visibility": ui_visibility, "weight": 0} + queryStr = "INSERT INTO public.ice_deployment_target( \ + uuid, name, version, ui_visibility, weight) \ + VALUES ('%s', '%s', '%s', '%s', %s);" % (new_aic_version['uuid'], new_aic_version['name'], new_aic_version['version'], new_aic_version['ui_visibility'], new_aic_version['weight']) + DBGeneral.insert_query(queryStr) + return new_aic_version + + @staticmethod + def delete_aic_version(aic_uuid): + DBGeneral.insert_query( + "DELETE FROM public.ice_deployment_target WHERE uuid='%s';" % aic_uuid) + + @staticmethod + def change_aic_version_weight(new_weight, old_weight): + DBGeneral.insert_query( + "UPDATE public.ice_deployment_target SET weight=%s WHERE weight=%s" % (new_weight, old_weight)) + + @staticmethod + def change_ecomp_release_weight(new_weight, old_weight): + DBGeneral.insert_query( + "UPDATE public.ice_ecomp_release SET weight=%s WHERE weight=%s" % (new_weight, old_weight)) + + @staticmethod + def select_aic_version_uuid(aic_version): + return DBGeneral.select_where("uuid", "ice_deployment_target", "version", aic_version, 1) + + @staticmethod + def select_ecomp_release_uuid(ecomp_release): + return DBGeneral.select_where("uuid", "ice_ecomp_release", "name", ecomp_release, 1) + + @staticmethod + def add_admin_to_eng_team(eng_uuid): + admin_db_id = DBGeneral.select_where( + 'id', Constants.DBConstants.IceTables.USER_PROFILE, 'email', Constants.Users.Admin.EMAIL, 1) + queryStr = "INSERT INTO public.ice_engagement_engagement_team(engagement_id, iceuserprofile_id) VALUES ('%s', '%s');" % ( + eng_uuid, admin_db_id) + logger.debug("add_admin_to_eng_team Query: %s" % queryStr) + DBGeneral.insert_query(queryStr) + + @staticmethod + def remove_engagement_from_recent(vf_uuid): + DBGeneral.insert_query( + "DELETE FROM %s WHERE vf_id='%s'" % (Constants.DBConstants.IceTables.RECENT, vf_uuid)) diff --git a/services/frontend/__init__.py b/services/frontend/__init__.py new file mode 100644 index 0000000..30d7152 --- /dev/null +++ b/services/frontend/__init__.py @@ -0,0 +1,38 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. diff --git a/services/frontend/__pycache__/__init__.cpython-36.pyc b/services/frontend/__pycache__/__init__.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..bd6d49d --- /dev/null +++ b/services/frontend/__pycache__/__init__.cpython-36.pyc diff --git a/services/frontend/__pycache__/fe_checklist.cpython-36.pyc b/services/frontend/__pycache__/fe_checklist.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..d743311 --- /dev/null +++ b/services/frontend/__pycache__/fe_checklist.cpython-36.pyc diff --git a/services/frontend/__pycache__/fe_checklist_template.cpython-36.pyc b/services/frontend/__pycache__/fe_checklist_template.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..c781628 --- /dev/null +++ b/services/frontend/__pycache__/fe_checklist_template.cpython-36.pyc diff --git a/services/frontend/__pycache__/fe_cms.cpython-36.pyc b/services/frontend/__pycache__/fe_cms.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..b1c3fbe --- /dev/null +++ b/services/frontend/__pycache__/fe_cms.cpython-36.pyc diff --git a/services/frontend/__pycache__/fe_dashboard.cpython-36.pyc b/services/frontend/__pycache__/fe_dashboard.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..5222e8e --- /dev/null +++ b/services/frontend/__pycache__/fe_dashboard.cpython-36.pyc diff --git a/services/frontend/__pycache__/fe_detailed_view.cpython-36.pyc b/services/frontend/__pycache__/fe_detailed_view.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..6247ca3 --- /dev/null +++ b/services/frontend/__pycache__/fe_detailed_view.cpython-36.pyc diff --git a/services/frontend/__pycache__/fe_general.cpython-36.pyc b/services/frontend/__pycache__/fe_general.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..9b19b20 --- /dev/null +++ b/services/frontend/__pycache__/fe_general.cpython-36.pyc diff --git a/services/frontend/__pycache__/fe_invite.cpython-36.pyc b/services/frontend/__pycache__/fe_invite.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..2a94d33 --- /dev/null +++ b/services/frontend/__pycache__/fe_invite.cpython-36.pyc diff --git a/services/frontend/__pycache__/fe_overview.cpython-36.pyc b/services/frontend/__pycache__/fe_overview.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..eee24cc --- /dev/null +++ b/services/frontend/__pycache__/fe_overview.cpython-36.pyc diff --git a/services/frontend/__pycache__/fe_user.cpython-36.pyc b/services/frontend/__pycache__/fe_user.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..54cb26d --- /dev/null +++ b/services/frontend/__pycache__/fe_user.cpython-36.pyc diff --git a/services/frontend/__pycache__/fe_wizard.cpython-36-PYTEST.pyc b/services/frontend/__pycache__/fe_wizard.cpython-36-PYTEST.pyc Binary files differnew file mode 100755 index 0000000..630c015 --- /dev/null +++ b/services/frontend/__pycache__/fe_wizard.cpython-36-PYTEST.pyc diff --git a/services/frontend/__pycache__/fe_wizard.cpython-36.pyc b/services/frontend/__pycache__/fe_wizard.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..ca7c26f --- /dev/null +++ b/services/frontend/__pycache__/fe_wizard.cpython-36.pyc diff --git a/services/frontend/base_actions/__init__.py b/services/frontend/base_actions/__init__.py new file mode 100644 index 0000000..30d7152 --- /dev/null +++ b/services/frontend/base_actions/__init__.py @@ -0,0 +1,38 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. diff --git a/services/frontend/base_actions/__pycache__/__init__.cpython-36.pyc b/services/frontend/base_actions/__pycache__/__init__.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..567e40e --- /dev/null +++ b/services/frontend/base_actions/__pycache__/__init__.cpython-36.pyc diff --git a/services/frontend/base_actions/__pycache__/click.cpython-36.pyc b/services/frontend/base_actions/__pycache__/click.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..7848aff --- /dev/null +++ b/services/frontend/base_actions/__pycache__/click.cpython-36.pyc diff --git a/services/frontend/base_actions/__pycache__/enter.cpython-36.pyc b/services/frontend/base_actions/__pycache__/enter.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..df5e175 --- /dev/null +++ b/services/frontend/base_actions/__pycache__/enter.cpython-36.pyc diff --git a/services/frontend/base_actions/__pycache__/get.cpython-36.pyc b/services/frontend/base_actions/__pycache__/get.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..a95dc14 --- /dev/null +++ b/services/frontend/base_actions/__pycache__/get.cpython-36.pyc diff --git a/services/frontend/base_actions/__pycache__/wait.cpython-36.pyc b/services/frontend/base_actions/__pycache__/wait.cpython-36.pyc Binary files differnew file mode 100644 index 0000000..29b73ba --- /dev/null +++ b/services/frontend/base_actions/__pycache__/wait.cpython-36.pyc diff --git a/services/frontend/base_actions/click.py b/services/frontend/base_actions/click.py new file mode 100644 index 0000000..00470b7 --- /dev/null +++ b/services/frontend/base_actions/click.py @@ -0,0 +1,108 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +from selenium.webdriver.common.action_chains import ActionChains + +from services.frontend.base_actions.wait import Wait +from services.session import session + + +class Click: + + @staticmethod + def id(element_id, wait_for_page=False): + try: + if wait_for_page: + Wait.page_has_loaded() + Wait.id(element_id) + session.ice_driver.find_element_by_id(element_id).click() + except Exception as e: # If failed - count the failure and add the error to list of errors. + errorMsg = "Failed to click_on on ID " + element_id + raise Exception(errorMsg, e) + + @staticmethod + def name(element_name, wait_for_page=False): + try: + if wait_for_page: + Wait.page_has_loaded() + Wait.name(element_name) + session.ice_driver.find_element_by_name(element_name).click() + except Exception as e: # If failed - count the failure and add the error to list of errors. + errorMsg = "Failed to click_on on ID " + element_name + raise Exception(errorMsg, e) + + @staticmethod + def link_text(link_inner_text, wait_for_page=False): + try: + if wait_for_page: + Wait.page_has_loaded() + Wait.link_text(link_inner_text) + session.ice_driver.find_element_by_link_text(link_inner_text).click() + except Exception as e: # If failed - count the failure and add the error to list of errors. + errorMsg = "Failed to click_on on LINK TEXT " + link_inner_text + raise Exception(errorMsg, e) + + @staticmethod + def css(element_css, wait_for_page=False): + try: + if wait_for_page: + Wait.page_has_loaded() + Wait.css(element_css) + session.ice_driver.find_element_by_css_selector(element_css).click() + except Exception as e: # If failed - count the failure and add the error to list of errors. + errorMsg = "Failed to click_on on CSS Selector " + element_css + raise Exception(errorMsg, e) + + @staticmethod + def xpath(element_xpath, wait_for_page=False): + try: + if wait_for_page: + Wait.page_has_loaded() + Wait.xpath(element_xpath) + session.ice_driver.find_element_by_xpath(element_xpath).click() + except Exception as e: # If failed - count the failure and add the error to list of errors. + errorMsg = "Failed to click_on on XPATH " + element_xpath + raise Exception(errorMsg, e) + + @staticmethod + def drag_and_drop_by_css(source_css, xoffset, yoffset): + ns = session.ice_driver.find_element_by_id("step-description-1") + ActionChains(session.ice_driver).move_to_element(ns).perform() + Wait.css(source_css) + source_element = session.ice_driver.find_element_by_css_selector(source_css) + ActionChains(session.ice_driver).drag_and_drop_by_offset(source_element, xoffset, yoffset).perform() diff --git a/services/frontend/base_actions/enter.py b/services/frontend/base_actions/enter.py new file mode 100644 index 0000000..4577a3d --- /dev/null +++ b/services/frontend/base_actions/enter.py @@ -0,0 +1,139 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +from datetime import datetime +import time + +from services.frontend.base_actions.wait import Wait +from services.logging_service import LoggingServiceFactory +from services.session import session + + +logger = LoggingServiceFactory.get_logger() +class Enter: + + @staticmethod + def text_by_name(attr_name_value, typed_text, wait_for_page=False): + try: # Send keys to element in UI, by name locator (e.g. type something in text box). + if wait_for_page: + Wait.page_has_loaded() + Wait.name(attr_name_value) + session.ice_driver.find_element_by_name(attr_name_value).clear() + session.ice_driver.find_element_by_name(attr_name_value).send_keys(typed_text[:-1]) + time.sleep(session.wait_until_time_pause) + session.ice_driver.find_element_by_name(attr_name_value).send_keys(typed_text[-1:]) + except Exception as e: # If failed - count the failure and add the error to list of errors. + errorMsg = "Failed to type " + typed_text + " in text box" + raise Exception(errorMsg, e) + + @staticmethod + def text_by_xpath(attr_xpath_value, typed_text, wait_for_page=False): + try: # Send keys to element in UI, by name locator (e.g. type something in text box). + if wait_for_page: + Wait.page_has_loaded() + Wait.xpath(attr_xpath_value) + session.ice_driver.find_element_by_xpath(attr_xpath_value).clear() + session.ice_driver.find_element_by_xpath(attr_xpath_value).send_keys(typed_text[:-1]) + time.sleep(session.wait_until_time_pause) + session.ice_driver.find_element_by_xpath(attr_xpath_value).send_keys(typed_text[-1:]) + except Exception as e: # If failed - count the failure and add the error to list of errors. + errorMsg = "Failed to type " + typed_text + " in text box" + raise Exception(errorMsg, attr_xpath_value) + + @staticmethod + def text_by_id(attr_id_value, typed_text, wait_for_page=False): + try: # Send keys to element in UI, by ID locator (e.g. type something in text box). + if wait_for_page: + Wait.page_has_loaded() + Wait.id(attr_id_value) + session.ice_driver.find_element_by_id(attr_id_value).clear() + session.ice_driver.find_element_by_id(attr_id_value).send_keys(typed_text[:-1]) + time.sleep(session.wait_until_time_pause) + session.ice_driver.find_element_by_id(attr_id_value).send_keys(typed_text[-1:]) + except Exception as e: # If failed - count the failure and add the error to list of errors. + errorMsg = "Failed to type " + typed_text + " in text box" + raise Exception(errorMsg, attr_id_value) + + @staticmethod + def clear(attr_id_value): + try: + Wait.id(attr_id_value) + session.ice_driver.find_element_by_id(attr_id_value).clear() + except Exception as e: + errorMsg = "Failed to clear text box" + raise Exception(errorMsg, attr_id_value) + + @staticmethod + def text_by_css(attr_css_value, typed_text, wait_for_page=False): + try: # Send keys to element in UI, by CSS locator (e.g. type something in text box). + if wait_for_page: + Wait.page_has_loaded() + Wait.css(attr_css_value) + session.ice_driver.find_element_by_css_selector(attr_css_value).clear() + session.ice_driver.find_element_by_css_selector(attr_css_value).send_keys(typed_text[:-1]) + time.sleep(session.wait_until_time_pause) + session.ice_driver.find_element_by_css_selector(attr_css_value).send_keys(typed_text[-1:]) + except Exception as e: # If failed - count the failure and add the error to list of errors. + errorMsg = "Failed to type " + typed_text + " in text box" + raise Exception(errorMsg, attr_css_value) + + @staticmethod + def text_by_link_text(attr_link_text_value, typed_text, wait_for_page=False): + try: # Send keys to element in UI, by name locator (e.g. type something in text box). + if wait_for_page: + Wait.page_has_loaded() + Wait.link_text(attr_link_text_value) + session.ice_driver.find_element_by_link_text(attr_link_text_value).clear() + session.ice_driver.find_element_by_link_text(attr_link_text_value).send_keys(typed_text[:-1]) + time.sleep(session.wait_until_time_pause) + session.ice_driver.find_element_by_link_text(attr_link_text_value).send_keys(typed_text[-1:]) + except Exception as e: # If failed - count the failure and add the error to list of errors. + errorMsg = "Failed to type " + typed_text + " in text box" + raise Exception(errorMsg, attr_link_text_value) + + @staticmethod + def date_picker(selector, property_name, wait_for_page=False): + try: + if wait_for_page: + Wait.page_has_loaded() + session.ice_driver.execute_script( + "var element = angular.element(document.querySelector('" + selector + "')); element.scope()." + + property_name + " = new Date('" + str(datetime.today().isoformat()) + "')") + except Exception as e: + errorMsg = "Failed to select date with datePicker." + raise Exception(errorMsg, str(e)) diff --git a/services/frontend/base_actions/get.py b/services/frontend/base_actions/get.py new file mode 100644 index 0000000..8735c1b --- /dev/null +++ b/services/frontend/base_actions/get.py @@ -0,0 +1,127 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +from services.frontend.base_actions.wait import Wait +from services.session import session + + +class Get: + + @staticmethod + def by_id(attr_id_value, wait_for_page=False): + try: + if wait_for_page: + Wait.page_has_loaded() + Wait.id(attr_id_value) + return session.ice_driver.find_element_by_id(attr_id_value).text + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "Failed to get text of element " + attr_id_value + raise Exception(errorMsg, attr_id_value) + + @staticmethod + def by_css(attr_css_value, wait_for_page=False): + try: + if wait_for_page: + Wait.page_has_loaded() + Wait.css(attr_css_value) + return session.ice_driver.find_element_by_css_selector(attr_css_value).text + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "Failed to get text of element " + attr_css_value + raise Exception(errorMsg, attr_css_value) + + @staticmethod + def wysiwyg_element_by_id(attr_id_value): + try: + Wait.id(attr_id_value) + return session.ice_driver.find_element_by_css_selector( + "#" + attr_id_value + ".wysiwyg-textarea") + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "Failed to get element by id " + attr_id_value + raise Exception(errorMsg, attr_id_value) + + @staticmethod + def by_name(attr_name_value): + try: + Wait.name(attr_name_value) + return session.ice_driver.find_element_by_name(attr_name_value).text + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "Failed to get text of element " + attr_name_value + raise Exception(errorMsg, attr_name_value) + + @staticmethod + def by_xpath(attr_name_value): + try: + Wait.xpath(attr_name_value) + return session.ice_driver.find_element_by_xpath(attr_name_value).text + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "Failed to get text of element " + attr_name_value + raise Exception(errorMsg, attr_name_value) + + @staticmethod + def value_by_name(attr_name_value): + try: + Wait.name(attr_name_value) + return session.ice_driver.find_element_by_name(attr_name_value).get_attribute("value") + except Exception as e: + errorMsg = "Failed to get value by name:" + attr_name_value + raise Exception(errorMsg, attr_name_value) + + @staticmethod + def meta_order_by_id(attr_id_value): + try: + Wait.id(attr_id_value) + return session.ice_driver.find_element_by_id(attr_id_value).get_attribute("meta-order") + except Exception as e: + errorMsg = "Failed to get meta order by id:" + attr_id_value + raise Exception(errorMsg, attr_id_value) + + @staticmethod + def is_selected_by_id(attr_id_value, wait_for_page=False): + try: + if wait_for_page: + Wait.page_has_loaded() + Wait.id(attr_id_value) + return session.ice_driver.find_element_by_id(attr_id_value).is_selected() + except Exception as e: + errorMsg = "Failed to get if it's selected by id:" + attr_id_value + raise Exception(errorMsg, attr_id_value) diff --git a/services/frontend/base_actions/wait.py b/services/frontend/base_actions/wait.py new file mode 100644 index 0000000..50eff08 --- /dev/null +++ b/services/frontend/base_actions/wait.py @@ -0,0 +1,317 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +import time + +from selenium.common.exceptions import NoSuchElementException +from selenium.webdriver.common.by import By +from selenium.webdriver.support import expected_conditions +from selenium.webdriver.support.wait import WebDriverWait + +from services.constants import Constants +from services.logging_service import LoggingServiceFactory +from services.session import session + + +logger = LoggingServiceFactory.get_logger() + + +class Wait: + + @staticmethod + def text_by_xpath(xpath, text, wait_for_page=False): + try: # Wait 4 seconds for element and compare to expected result. + if wait_for_page: + Wait.page_has_loaded() + WebDriverWait(session.ice_driver, session.wait_until_retires).until( + expected_conditions.text_to_be_present_in_element( + (By.XPATH, xpath), text) + ) + # If failed - count the failure and add the error to list of errors. + except: + error_msg = "Text - " + text + " not found in xPath " + xpath + raise Exception(error_msg, xpath) + + @staticmethod + def text_by_id(element_id, text, wait_for_page=False): + try: # Wait 4 seconds for element and compare to expected result. + if wait_for_page: + Wait.page_has_loaded() + WebDriverWait(session.ice_driver, session.wait_until_retires).until( + expected_conditions.text_to_be_present_in_element( + (By.ID, element_id), text) + ) + # If failed - count the failure and add the error to list of errors. + except: + error_msg = "Text - " + text + " not found in ID " + element_id + raise Exception(error_msg, element_id) + + @staticmethod + def text_by_css(css, text, wait_for_page=False): + try: # Wait 4 seconds for element and compare to expected result. + if wait_for_page: + Wait.page_has_loaded() + WebDriverWait(session.ice_driver, session.wait_until_retires).until( + expected_conditions.text_to_be_present_in_element( + (By.CSS_SELECTOR, css), text) + ) + # If failed - count the failure and add the error to list of errors. + except Exception as e: + error_msg = "Text - " + text + " not found in CSS - " + css + raise Exception(error_msg, e) + + @staticmethod + def text_by_name(name, text, wait_for_page=False): + try: # Wait 4 seconds for element and compare to expected result. + if wait_for_page: + Wait.page_has_loaded() + WebDriverWait(session.ice_driver, session.wait_until_retires).until( + expected_conditions.text_to_be_present_in_element( + (By.NAME, name), text) + ) + # If failed - count the failure and add the error to list of errors. + except Exception as e: + error_msg = "Text - " + text + " not found by NAME - " + name + raise Exception(error_msg, e) + + @staticmethod + def id(element_id, wait_for_page=False): + try: # Wait 4 seconds for element and compare to expected result. + if wait_for_page: + Wait.page_has_loaded() + WebDriverWait(session.ice_driver, session.wait_until_retires).until( + expected_conditions.visibility_of_element_located( + (By.ID, element_id)) + ) + # If failed - count the failure and add the error to list of errors. + except Exception as e: + error_msg = "Didn't find ID " + element_id + raise Exception(error_msg, e) + + @staticmethod + def css(element_css, wait_for_page=False): + try: # Wait 4 seconds for element and compare to expected result. + if wait_for_page: + Wait.page_has_loaded() + WebDriverWait(session.ice_driver, session.wait_until_retires).until( + expected_conditions.visibility_of_element_located( + (By.CSS_SELECTOR, element_css)) + ) + # If failed - count the failure and add the error to list of errors. + except Exception as e: + error_msg = "Didn't find CSS Selector " + element_css + raise Exception(error_msg, e) + + @staticmethod + def is_css_exists(element_css, wait_for_page=False): + try: # Wait 4 seconds for element and compare to expected result. + if wait_for_page: + Wait.page_has_loaded() + WebDriverWait(session.ice_driver, session.wait_until_implicit_time).until( + expected_conditions.visibility_of_element_located( + (By.CSS_SELECTOR, element_css)) + ) + return True + # If failed - count the failure and add the error to list of errors. + except Exception as e: + error_msg = "Didn't find CSS Selector " + element_css + return False + + @staticmethod + def link_text(link_inner_text, wait_for_page=False): + try: + if wait_for_page: + Wait.page_has_loaded() + WebDriverWait(session.ice_driver, session.wait_until_retires).until( + expected_conditions.visibility_of_element_located( + (By.LINK_TEXT, link_inner_text)) + ) + # If failed - count the failure and add the error to list of errors. + except Exception as e: + error_msg = "Didn't find LINK TEXT " + link_inner_text + raise Exception(error_msg, e) + + @staticmethod + def name(element_name, wait_for_page=False): + try: + if wait_for_page: + Wait.page_has_loaded() + WebDriverWait(session.ice_driver, session.wait_until_retires).until( + expected_conditions.visibility_of_element_located( + (By.NAME, element_name)) + ) + # If failed - count the failure and add the error to list of errors. + except Exception as e: + error_msg = "Didn't find NAME " + element_name + raise Exception(error_msg, e) + + @staticmethod + def xpath(element_xpath, wait_for_page=False): + try: + if wait_for_page: + Wait.page_has_loaded() + WebDriverWait(session.ice_driver, session.wait_until_retires).until( + expected_conditions.visibility_of_element_located( + (By.XPATH, element_xpath)) + ) + # If failed - count the failure and add the error to list of errors. + except Exception as e: + error_msg = "Didn't find XPath " + element_xpath + raise Exception(error_msg, e) + + @staticmethod + def page_has_loaded(): + countwait_untilelement_to_be_presented_by_id = 0 + for _ in range(Constants.FEConstants.RETRIES_NUMBER): + httpRequests = session.ice_driver.execute_script( + 'return window.angular ? window.angular.element("body").injector().get("$http").pendingRequests.length : 1;') + if(str(httpRequests) == "0"): + time.sleep(session.wait_until_time_pause) + return + logger.debug( + "Checking if {} page is loaded. ".format(session.ice_driver.current_url)) + time.sleep(session.wait_until_time_pause) + countwait_untilelement_to_be_presented_by_id += 1 + + raise Exception("Page loading took too much time") + + @staticmethod + def modal_to_dissappear(): + session.ice_driver.implicitly_wait(0) + i = 0 + not_found = False + while i < session.wait_until_retires: + try: + session.ice_driver.find_element_by_css_selector( + Constants.Dashboard.Wizard.Open.CSS) + except NoSuchElementException: + not_found = True + try: + session.ice_driver.find_element_by_class_name( + Constants.Dashboard.Wizard.Open.CLASS_NAME) + not_found = False + except NoSuchElementException: + not_found = True + + if not_found: + break + + else: + time.sleep(session.wait_until_time_pause) + i += 1 + + session.ice_driver.implicitly_wait(session.wait_until_implicit_time) + if not_found: + return True + else: + raise Exception("waitForModalToDissapper") + + @staticmethod + def id_to_dissappear(id_element, wait_for_page=False): + if wait_for_page: + Wait.page_has_loaded() + session.ice_driver.implicitly_wait(0) + i = 0 + not_found = False + while i < session.wait_until_retires: + try: + session.ice_driver.find_element_by_id(id_element) + except NoSuchElementException: + not_found = True + + if not_found: + break + else: + time.sleep(session.wait_until_time_pause) + i += 1 + + session.ice_driver.implicitly_wait(session.wait_until_implicit_time) + if not_found: + return True + else: + raise Exception( + "id_to_dissappear " + id_element + " num of retries = " + str(i)) + + @staticmethod + def name_to_dissappear(name_element, wait_for_page=False): + if wait_for_page: + Wait.page_has_loaded() + session.ice_driver.implicitly_wait(0) + i = 0 + not_found = False + while i < session.wait_until_retires: + try: + session.ice_driver.find_element_by_name(name_element) + except NoSuchElementException: + not_found = True + + if not_found: + break + else: + time.sleep(session.wait_until_time_pause) + i += 1 + + session.ice_driver.implicitly_wait(session.wait_until_implicit_time) + if not_found: + return True + else: + raise Exception( + "name_to_dissappear " + name_element + " num of retries = " + str(i)) + + @staticmethod + def css_to_dissappear(css_element): + session.ice_driver.implicitly_wait(0) + i = 0 + not_found = False + while i < session.wait_until_retires: + try: + session.ice_driver.find_element_by_css_selector(css_element) + except NoSuchElementException: + not_found = True + + if not_found: + break + else: + time.sleep(session.wait_until_time_pause) + i += 1 + + session.ice_driver.implicitly_wait(session.wait_until_implicit_time) + if not_found: + return True + else: + raise Exception("css_to_dissappear" + css_element) diff --git a/services/frontend/fe_checklist.py b/services/frontend/fe_checklist.py new file mode 100644 index 0000000..75f957a --- /dev/null +++ b/services/frontend/fe_checklist.py @@ -0,0 +1,755 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +from django.conf import settings +from selenium.webdriver.support.ui import Select +from wheel.signatures import assertTrue + +from services.database.db_checklist import DBChecklist +from services.database.db_user import DBUser +from services.database.db_virtual_function import DBVirtualFunction +from services.frontend.base_actions.click import Click +from services.frontend.base_actions.enter import Enter +from services.frontend.base_actions.get import Get +from services.frontend.base_actions.wait import Wait +from services.frontend.fe_general import FEGeneral +from services.frontend.fe_overview import FEOverview +from services.frontend.fe_user import FEUser +from services.frontend.fe_wizard import FEWizard +from services.helper import Helper +from services.logging_service import LoggingServiceFactory +from tests.uiTests.test_ui_base import * + + +logger = LoggingServiceFactory.get_logger() + + +class FEChecklist: + + assocciatedFileName = None + + @staticmethod + def go_to_checklist(engagement_id, cl_uuid): + try: + Click.id(engagement_id) + Click.id("checklist-" + cl_uuid) + Wait.id("line-item-description") + except Exception as e: + errorMsg = "Failed to go to checklist page." + raise Exception(errorMsg, e) + + @staticmethod + def create_new_checklist(newObj): + try: + newObjWithChecklist = None + vfName = newObj[0] + uuid = newObj[1] + inviteEmail = newObj[2] + # Fetch one AT&T user ID. + vfuuid = DBGeneral.select_where( + "uuid", "ice_vf", "name", vfName, 1) + engagement_id = DBVirtualFunction.select_eng_uuid(vfName) + engLeadEmail = DBUser.select_el_email(vfName) + logger.debug("EL email: " + engLeadEmail) + engagement_manual_id = DBGeneral.select_where("engagement_manual_id", "ice_engagement", "uuid", + engagement_id, 1) + # Click on all default next steps + myVfName = engagement_manual_id + ": " + vfName + actualVfNameid = "clickable-" + myVfName + actualVfName = Get.by_id(actualVfNameid) + Helper.internal_assert(myVfName, actualVfName) + # NEXT STEP ID + Click.id(actualVfNameid, wait_for_page=True) + FEOverview.complete_defaults_nextsteps(engagement_id) + inviterURL = Constants.Default.InviteURL.Signup.TEXT + \ + vfuuid + "&inviter_uuid=" + uuid + "&email=" + inviteEmail +# time.sleep(2) + FEGeneral.re_open(inviterURL) + FEGeneral.form_validate_email(inviteEmail) + # Login with EL role + FEGeneral.re_open(Constants.Default.LoginURL.TEXT) + FEUser.login(engLeadEmail, Constants.Default.Password.TEXT) + Wait.id(Constants.Dashboard.Statuses.Title.ID) + Wait.id(engagement_manual_id) # cheklist + # VALIDATE SCROLLING + actualVfName = Get.by_id(actualVfNameid) + myVfName = engagement_manual_id + ": " + vfName +# Wait.id(actualVfNameid) + Wait.id(engagement_manual_id, wait_for_page=True) + Click.id(actualVfNameid, wait_for_page=True) + # Create new checklist + checklistName = FEChecklist.create_checklist( + engagement_id, vfName, actualVfName, engagement_manual_id) + checklistUuid = DBGeneral.select_where( + "uuid", "ice_checklist", "name", checklistName, 1) + newObjWithChecklist = [checklistUuid, engLeadEmail, engagement_manual_id, actualVfNameid, myVfName, + checklistName] + return newObjWithChecklist + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "Failed to create checklist." + str(e) + raise Exception(errorMsg, "create_new_checklist") + + @staticmethod + def create_checklist(engagement_id, vfName, actualVfName, engagement_manual_id): + try: + checklistName = Helper.rand_string("randomString") + Wait.id("checklist-plus-" + engagement_id, wait_for_page=True) + + Click.id("checklist-plus-" + engagement_id, wait_for_page=True) + + Helper.internal_assert( + "Create Checklist", Get.by_id("modal-header-checklist-15")) + # vm.checkListName + Enter.text_by_name( + "checkListName", checklistName, wait_for_page=True) + Wait.xpath("//select") + + Select(session.ice_driver.find_element_by_id(Constants.Template.Subtitle.SelectTemplateTitle.TEXT) + ).select_by_visible_text(Constants.Template.Heat.TEXT) + Click.id(Constants.Template.Heat.TEXT, wait_for_page=True) +# Click.css("option.ng-binding.ng-scope") + Helper.internal_assert( + "Associate Files", Get.by_id("associated-files-title", wait_for_page=True)) + Click.xpath("//multiselect/div/button", wait_for_page=True) + Click.link_text("file0", wait_for_page=True) + Click.link_text("file1") + Wait.text_by_css(Constants.SubmitButton.CSS, "Create Checklist") + Click.id(Constants.Dashboard.LeftPanel.CreateChecklist.ID) + Wait.modal_to_dissappear() + Wait.id(engagement_manual_id) + return checklistName + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "Failed to create checklist." + str(e) + raise Exception(errorMsg, "create_checklist") + + @staticmethod + def update_cl_name_and_associated_files(engagement_manual_id): + Click.id("edit-checklist", True) + Wait.text_by_id("modal-header-checklist-15", "Update Checklist") + newfileName = "file" + Helper.rand_string("randomString") + Enter.text_by_xpath("//div[3]/div/div/input", newfileName) + updatedFileName = "file2" + # Select associated files from multi-select drop-down. + Click.xpath("//multiselect/div/button") + Click.link_text("file2") + Click.css(Constants.SubmitButton.CSS) + Wait.id(engagement_manual_id) + newFileNames = [newfileName, updatedFileName] + return newFileNames + + @staticmethod + def update_cl_associated_files(engagement_manual_id): + Click.id("edit-checklist", True) + Wait.text_by_id("modal-header-checklist-15", "Update Checklist") + # Select associated files from multi-select drop-down. + Click.xpath("//multiselect/div/button") + Click.link_text("file2") + Click.xpath("//multiselect/div/button") + Click.css(Constants.SubmitButton.CSS) + Wait.id(engagement_manual_id, True) + + @staticmethod + def add_next_step(checklistName, newObj): + Click.id(Constants.Dashboard.Checklist.AddNS.ID, wait_for_page=True) + Wait.text_by_css("span.font_header", "Checklist:") + Helper.internal_assert("Checklist:", Get.by_css("span.font_header")) + Helper.internal_assert("Add Next Steps", Get.by_css("h2")) + # First NS + Click.id("description") + Enter.text_by_id("description", "description of NS") + Click.css("div.modal-content") + Click.xpath("(//button[@type='button'])[10]") + FEChecklist.assocciatedFileName = "file0" + Click.link_text(FEChecklist.assocciatedFileName) + Click.css("div.modal-content") + Click.xpath("(//button[@type='button'])[11]") + try: + Click.xpath("//div[3]/multiselect/div/ul/li/a") + except: + Click.link_text("Homer Simpson") + Click.css("div.modal-content") + count = 0 + FEWizard.date_picker_add_ns(count) + count = +1 + Click.css("span.add-text") + Click.xpath("(//div[@id='description'])[2]") + Enter.text_by_xpath( + "(//div[@id='description'])[2]", "description of NS2") + Click.css("div.modal-content") + Click.xpath("(//button[@type='button'])[14]") + Click.xpath("(//button[@type='button'])[22]") + Click.xpath("//div[3]/div/div[2]/multiselect/div/ul/li[2]/a") + Click.css("div.modal-content") + Click.xpath("(//button[@type='button'])[23]") + Click.css( + "div.btn-group.open > ul.dropdown-menu > li.ng-scope > a.ng-binding") + Click.link_text("Add Another Next Step") + Click.xpath("(//button[@type='button'])[25]") + FEWizard.date_picker_add_ns(count) + Click.xpath("//div[4]/div/span") + Helper.internal_assert("Submit Next Steps", Get.by_id("btn-submit")) + Click.id("btn-submit", wait_for_page=True) + + @staticmethod + def add_next_step_updated(checklistName, newFileName): + Click.id(Constants.Dashboard.Checklist.AddNS.ID) + Wait.id(Constants.Dashboard.Modal.CLOSE_BUTTON_ID) + Wait.text_by_css("span.font_header.ng-binding", "Checklist:") + Wait.text_by_css("h2.ng-binding", "Add Next Steps") + # First NS + Click.id("description") + Enter.text_by_id("description", "description of NS") + Click.css("div.modal-content") + Click.xpath("(//button[@type='button'])[10]") + Click.link_text(newFileName) + Click.css("div.modal-content") + Click.xpath("(//button[@type='button'])[11]") + try: + Click.xpath("//div[3]/multiselect/div/ul/li/a") + except: + Wait.link_text("Homer Simpson") + Click.link_text("Homer Simpson") + Wait.css("div.modal-content") + Click.css("div.modal-content") + Wait.xpath("(//button[@type='button'])[12]") + count = 0 + FEWizard.date_picker_add_ns(count) + count = +1 + Click.css("span.add-text") + Click.xpath("(//div[@id='description'])[2]") + Enter.text_by_xpath( + "(//div[@id='description'])[2]", "description of NS2") + Click.css("div.modal-content") + Click.xpath("(//button[@type='button'])[14]") + Click.xpath("(//button[@type='button'])[22]") + Click.xpath("//div[3]/div/div[2]/multiselect/div/ul/li[2]/a") + Click.css("div.modal-content") + Click.xpath("(//button[@type='button'])[23]") + Click.css( + "div.btn-group.open > ul.dropdown-menu > li.ng-scope > a.ng-binding") + Click.link_text("Add Another Next Step") + Wait.xpath("(//button[@type='button'])[25]") + Click.xpath("(//button[@type='button'])[25]") + Wait.xpath("(//button[@type='button'])[24]") + FEWizard.date_picker_add_ns(count) + Wait.xpath("//div[4]/div/span") + Click.xpath("//div[4]/div/span") + Wait.id("btn-submit") + Wait.text_by_id("btn-submit", "Submit Next Steps") +# Helper.internal_assert("Submit Next Steps", Get.by_id("btn-submit")) + Click.id("btn-submit") + + @staticmethod + def approval_state_actions_and_validations(checklistName, newObj, state): + # REWVIEW STEPS AND VALIDATIONS + try: + Wait.id("checklist-main-section") + Wait.text_by_id( + Constants.Dashboard.Checklist.Name.ID, checklistName) + try: + if settings.DATABASE_TYPE == 'local': + Wait.text_by_css( + "h2.ng-binding", "Section 1: Parameter Specification") + Helper.internal_assert( + "Parameters", Get.by_css("span.col-md-9.ng-binding")) + Helper.internal_assert( + "String parameters", Get.by_xpath("//li[2]/span[2]")) + Helper.internal_assert( + "Numeric parameters", Get.by_xpath("//li[3]/span[2]")) + if settings.DATABASE_TYPE == 'local': + Helper.internal_assert("Section 2: External References", + Get.by_xpath("//li[2]/h2")) + # //li[2]/ul/li/span[2] #//ul[@id='line-item-list']/li[2]/ul/li/span[2] + Helper.internal_assert( + "Normal references", Get.by_xpath("//li[2]/ul/li/span[2]")) + Helper.internal_assert( + "VF image", Get.by_xpath("//li[2]/ul/li[2]/span[2]")) + except: + if settings.DATABASE_TYPE == 'local': + Wait.text_by_css( + "h2.ng-binding", "Section 1: External References") + try: + Helper.internal_assert( + "Normal references", Get.by_css("span.col-md-9.ng-binding")) + except: + if "VF image" in Get.by_xpath("//li[2]/span[2]"): + logger.debug("All Ok") + if settings.DATABASE_TYPE == 'local': + Helper.internal_assert( + "Section 2: Parameter Specification", Get.by_xpath("//li[2]/h2")) + try: + if settings.DATABASE_TYPE == 'local': + Helper.internal_assert( + "1.1 - Parameters", Get.by_xpath("//header/h2")) + except: + if settings.DATABASE_TYPE == 'local': + Helper.internal_assert( + "1.1 - Normal References", Get.by_xpath("//header/h2")) + if settings.DATABASE_TYPE == 'local': + elementTxt = Get.by_id("line-item-description") + Helper.internal_assert( + "Numeric parameters should include range and/or allowed values.", elementTxt) + Helper.internal_assert("Audit Logs", Get.by_css("h3.col-md-12")) + localLogText = "local log" + Enter.text_by_id("new-audit-log-text", localLogText) + Helper.internal_assert( + "Add Log Entry", Get.by_id("submit-new-audit-lop-text")) + Click.id("submit-new-audit-lop-text") + vfName = newObj[0] + engLeadFullName = DBUser.get_el_name(vfName) + Helper.internal_assert(localLogText, Get.by_css( + Constants.Dashboard.Checklist.AuditLog.LastLocalAuditLog.CSS)) + try: + if settings.DATABASE_TYPE == 'local': + Helper.internal_assert( + "Parameters", Get.by_xpath("//li[2]/ul/li/span[2]")) + except: + if settings.DATABASE_TYPE == 'local': + Helper.internal_assert( + "Numeric parameters", Get.by_xpath("//li[2]/ul/li/span[2]")) + +# if Wait.css(Constants.Dashboard.Checklist.LineItem.Deny.CSS) or +# Wait.css(Constants.Dashboard.Checklist.LineItem.Approve.CSS): + session.run_negative(lambda: Wait.css(Constants.Dashboard.Checklist.LineItem.Deny.CSS) or Wait.css( + Constants.Dashboard.Checklist.LineItem.Approve.CSS), "Buttons displayed for Admin it's NOT work") +# logger.debug("Buttons displayed for Admin it's NOT work") +# else: +# print("Buttons not displayed for Admin it's work") + if state == "APPROVAL": + if settings.DATABASE_TYPE == 'local': + Helper.internal_assert( + "Audit Log (6)", Get.by_id(Constants.Dashboard.Checklist.AuditLog.ID)) + else: + Helper.internal_assert( + "Audit Log (7)", Get.by_id(Constants.Dashboard.Checklist.AuditLog.ID)) + if state == "HANDOFF": + if settings.DATABASE_TYPE == 'local': + Helper.internal_assert( + "Audit Log (8)", Get.by_id(Constants.Dashboard.Checklist.AuditLog.ID)) + else: + Helper.internal_assert( + "Audit Log (9)", Get.by_id(Constants.Dashboard.Checklist.AuditLog.ID)) + Click.id(Constants.Dashboard.Checklist.AuditLog.ID) + Wait.text_by_xpath("//span[2]", checklistName) + engLeadFullName = DBUser.select_el_email(vfName) + Enter.text_by_xpath("//textarea", "zdfgsdyh") + Click.css(Constants.SubmitButton.CSS) + Wait.modal_to_dissappear() + if state == "APPROVAL": + if settings.DATABASE_TYPE == 'local': + Wait.text_by_id( + Constants.Dashboard.Checklist.AuditLog.ID, "Audit Log (7)") + else: + Wait.text_by_id( + Constants.Dashboard.Checklist.AuditLog.ID, "Audit Log (8)") + if state == "HANDOFF": + if settings.DATABASE_TYPE == 'local': + Wait.text_by_id( + Constants.Dashboard.Checklist.AuditLog.ID, "Audit Log (9)") + else: + Wait.text_by_id( + Constants.Dashboard.Checklist.AuditLog.ID, "Audit Log (10)") + if state == "APPROVAL": + Wait.text_by_xpath("//button[3]", "Add Next Steps") + Wait.text_by_id(Constants.Dashboard.Checklist.Reject.ID, + Constants.Dashboard.Checklist.Reject.Modal.Button.TEXT) + Wait.text_by_xpath( + "//div[@id='state-actions']/button", "Approve") + if state == "HANDOFF": + Wait.text_by_xpath( + "//div[@id='state-actions']/button", "Handoff complete?") + logger.debug("ALL VALIDATION PASS FOR STATE : " + state) + # If failed - count the failure and add the error to list of errors. + except Exception as e: + logger.error( + state + " state FAILED CONNECT TO STAGING MANUAL AND VERIFY WHY! ") + errorMsg = "approval_state_actions_and_validations FAILED because : " + \ + str(e) + raise Exception(errorMsg, "approval_state_actions_and_validations") + + @staticmethod + def review_state_actions_and_validations(checklistName, vfName, state): + try: + # REWVIEW STEPS AND VALIDATIONS + Wait.id("checklist-main-section") + Wait.text_by_id( + Constants.Dashboard.Checklist.Name.ID, checklistName) + try: + if settings.DATABASE_TYPE == 'local': + Helper.internal_assert( + "Section 1: Parameter Specification", Get.by_css("h2.ng-binding")) + Helper.internal_assert( + "Parameters", Get.by_css("span.col-md-9.ng-binding")) + Helper.internal_assert( + "String parameters", Get.by_xpath("//li[2]/span[2]")) + Helper.internal_assert( + "Numeric parameters", Get.by_xpath("//li[3]/span[2]")) + if settings.DATABASE_TYPE == 'local': + Helper.internal_assert( + "Section 2: External References", Get.by_xpath("//li[2]/h2")) + Helper.internal_assert( + "Normal references", Get.by_name("Normal references")) + Helper.internal_assert( + "VF image", Get.by_name("Normal references")) + except: + try: + Helper.internal_assert( + "Section 1: External References", Get.by_css("h2.ng-binding")) + except: + Helper.internal_assert( + "Section 1: Scaling Considerations", Get.by_css("h2.ng-binding")) + try: + Helper.internal_assert( + "Normal references", Get.by_css("span.col-md-9.ng-binding")) + except: + if "VF image" in Get.by_xpath("//li[2]/span[2]"): + logger.debug("All Ok") + if settings.DATABASE_TYPE == 'local': + Helper.internal_assert( + "Section 2: Parameter Specification", Get.by_xpath("//li[2]/h2")) + Click.name("VF image") + Click.name("Normal references") + try: + Helper.internal_assert( + "1.1 - Parameters", Get.by_xpath("//header/h2")) + except: + text = Get.by_name("Normal references") + Helper.internal_assert("Normal references", text) + Helper.internal_assert("Audit Logs", Get.by_css("h3.col-md-12")) + localLogText = "local log" + Enter.text_by_id("new-audit-log-text", localLogText) + Helper.internal_assert( + "Add Log Entry", Get.by_id("submit-new-audit-lop-text")) + Click.id("submit-new-audit-lop-text") + # Validate Local AuditLog + engLeadFullName = DBUser.get_el_name(vfName) + Helper.internal_assert( + engLeadFullName, Get.by_xpath("//ul[@id='audit-log-list']/li/h4")) + Helper.internal_assert(localLogText, Get.by_css( + Constants.Dashboard.Checklist.AuditLog.LastLocalAuditLog.CSS)) + if settings.DATABASE_TYPE == 'local': + try: + Helper.internal_assert( + "Parameters", Get.by_xpath("//li[2]/ul/li/span[2]")) + except: + Helper.internal_assert( + "Numeric parameters", Get.by_xpath("//li[2]/ul/li/span[2]")) + Click.name("Normal references") + Wait.css(Constants.Dashboard.Checklist.LineItem.Deny.CSS) + Wait.css(Constants.Dashboard.Checklist.LineItem.Approve.CSS) + Click.css(Constants.Dashboard.Checklist.LineItem.Approve.CSS) + # NOT LOCAL + if settings.DATABASE_TYPE != 'local': + checklistUuid = DBChecklist.get_recent_checklist_uuid( + checklistName)[0] + DBChecklist.update_all_decisions_to_approve(checklistUuid) + # NOT LOCAL + + Click.css(".line-item-row span.manual") + print("click on V button approve of decision in state = " + state) + try: + Wait.css("li.not-relevant-btn") + except: + Wait.xpath("//aside/header/ul/li") + if state == "review": + Wait.id("edit-checklist") + if state == "PEER": + if settings.DATABASE_TYPE == 'local': + Helper.internal_assert( + "Audit Log (4)", Get.by_id(Constants.Dashboard.Checklist.AuditLog.ID)) + else: + Helper.internal_assert( + "Audit Log (5)", Get.by_id(Constants.Dashboard.Checklist.AuditLog.ID)) + if state == "review": + if settings.DATABASE_TYPE == 'local': + Helper.internal_assert( + "Audit Log (2)", Get.by_id(Constants.Dashboard.Checklist.AuditLog.ID)) + else: + Helper.internal_assert( + "Audit Log (3)", Get.by_id(Constants.Dashboard.Checklist.AuditLog.ID)) + if state == "APPROVAL": + if settings.DATABASE_TYPE == 'local': + Helper.internal_assert( + "Audit Log (8)", Get.by_id(Constants.Dashboard.Checklist.AuditLog.ID)) + else: + Helper.internal_assert( + "Audit Log (9)", Get.by_id(Constants.Dashboard.Checklist.AuditLog.ID)) + Click.id( + Constants.Dashboard.Checklist.AuditLog.ID, wait_for_page=True) + Wait.text_by_xpath("//span[2]", checklistName) + Enter.text_by_xpath("//textarea", "zdfgsdyh") + Click.css(Constants.SubmitButton.CSS) + Wait.modal_to_dissappear() + if state == "review": + if settings.DATABASE_TYPE == 'local': + Helper.internal_assert( + "Audit Log (3)", Get.by_id(Constants.Dashboard.Checklist.AuditLog.ID)) + else: + Helper.internal_assert( + "Audit Log (4)", Get.by_id(Constants.Dashboard.Checklist.AuditLog.ID)) + if state == "PEER": + if settings.DATABASE_TYPE == 'local': + Helper.internal_assert( + "Audit Log (5)", Get.by_id(Constants.Dashboard.Checklist.AuditLog.ID)) + else: + Helper.internal_assert( + "Audit Log (6)", Get.by_id(Constants.Dashboard.Checklist.AuditLog.ID)) + if state == "APPROVAL": + if settings.DATABASE_TYPE == 'local': + Helper.internal_assert( + "Audit Log (9)", Get.by_id(Constants.Dashboard.Checklist.AuditLog.ID)) + else: + Helper.internal_assert( + "Audit Log (10)", Get.by_id(Constants.Dashboard.Checklist.AuditLog.ID)) + # Validate Buttons + if settings.DATABASE_TYPE != 'local': + FEGeneral.refresh() + engagement_id = DBVirtualFunction.select_eng_uuid(vfName) + engLeadEmail = DBUser.select_el_email(vfName) + logger.debug("EL email: " + engLeadEmail) + engagement_manual_id = DBGeneral.select_where("engagement_manual_id", "ice_engagement", + "uuid", engagement_id, 1) + # Click on all default next steps + myVfName = engagement_manual_id + ": " + vfName + actualVfNameid = "clickable-" + myVfName + Click.id(actualVfNameid) + Click.id("checklist-" + checklistUuid) + Helper.internal_assert( + "Add Next Steps", Get.by_xpath("//button[3]")) + Wait.text_by_id(Constants.Dashboard.Checklist.Reject.ID, + Constants.Dashboard.Checklist.Reject.Modal.Button.TEXT, wait_for_page=True) + Helper.internal_assert( + "Approve", Get.by_xpath("//div[@id='state-actions']/button")) + logger.debug("ALL VALIDATION PASS FOR STATE: " + state) + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "review_state_actions_and_validations FAILED because: " + \ + str(e) + raise Exception(errorMsg, "review_state_actions_and_validations") + logger.error( + state + " state FAILED CONNECT TO STAGING MANUAL AND VERIFY WHY!") + raise + + @staticmethod + def reject(rejectMsg=None): + try: + Click.id( + Constants.Dashboard.Checklist.Reject.ID, wait_for_page=True) + if rejectMsg: + Enter.text_by_name( + Constants.Dashboard.Checklist.Reject.Modal.Comment.NAME, rejectMsg, wait_for_page=True) + Click.id( + Constants.Dashboard.Checklist.Reject.Modal.Button.ID, wait_for_page=True) + except Exception as e: + errorMsg = "Failed to reject checklist." + raise Exception(errorMsg, e) + + @staticmethod + def add_line_item_audit_log(): + try: + log_txt = Helper.rand_string("randomString") + Enter.text_by_id("new-audit-log-text", log_txt, wait_for_page=True) + Click.id("submit-new-audit-lop-text") + Wait.text_by_css( + Constants.Dashboard.Checklist.AuditLog.LastLocalAuditLog.CSS, log_txt, wait_for_page=True) + return log_txt + except Exception as e: + errorMsg = "Failed to add audit log to line item." + raise Exception(errorMsg, e) + + @staticmethod + def click_on_checklist(user_content, checklistName, checklist_uuid=None): + FEOverview.click_on_vf(user_content) + if checklist_uuid is None: + checklist_uuid = DBGeneral.select_where_not_and_order_by_desc( + 'uuid', Constants.DBConstants.IceTables.CHECKLIST, 'name', checklistName, 'state', Constants.ChecklistStates.Archive.TEXT, 'create_time')[0] + Click.id("checklist-" + checklist_uuid) + + @staticmethod + def validate_reject_is_enabled(): + return Wait.id(Constants.Dashboard.Checklist.Reject.ID, wait_for_page=True) + + @staticmethod + def cl_to_next_stage(actualVfNameid): + Click.xpath("//div[@id='state-actions']/button", wait_for_page=True) + Wait.id(actualVfNameid, wait_for_page=True) + session.run_negative(lambda: Wait.css( + Constants.Default.BlockUI.CSS), "Error: CL to next stage failed.") + + @staticmethod + def search_by_vfname_for_not_local(user_content): + vfFullName = user_content[ + 'engagement_manual_id'] + ": " + user_content['vfName'] + if settings.DATABASE_TYPE != 'local': + Enter.text_by_id( + Constants.Dashboard.LeftPanel.SearchBox.ID, user_content['vfName']) + Click.css(Constants.Dashboard.LeftPanel.SearchBox.Results.CSS) + Wait.text_by_id( + Constants.Dashboard.Overview.Title.ID, vfFullName) + + @staticmethod + def search_by_manual_id(manual_id): + Enter.text_by_id( + Constants.Dashboard.LeftPanel.SearchBox.ID, manual_id, wait_for_page=True) + Click.css( + Constants.Dashboard.LeftPanel.SearchBox.Results.CSS, wait_for_page=True) + Wait.id(Constants.Dashboard.Overview.Title.ID) + + @staticmethod + def reject_checklist(newObj, checklistName): + Click.xpath("//button[2]") + vfName = newObj[0] + engLeadFullName = DBUser.get_el_name(vfName) + Enter.text_by_name( + Constants.Dashboard.Checklist.Reject.Modal.Comment.NAME, "Reject state By :" + engLeadFullName) + Helper.internal_assert( + "Checklist: " + checklistName, Get.by_css("span.state-title.ng-binding")) + Wait.text_by_id(Constants.Dashboard.Checklist.Reject.Modal.Button.ID, + Constants.Dashboard.Checklist.Reject.Modal.Button.TEXT) + Click.id(Constants.Dashboard.Checklist.Reject.Modal.Button.ID) + Wait.modal_to_dissappear() + + @staticmethod + def add_nsteps(checklistUuid, actualVfNameid, myVfName, checklistName, newFileNames): + Click.id(actualVfNameid, wait_for_page=True) + checklistUuid = DBChecklist.select_where_cl_not_archive( + "uuid", "ice_checklist", "name", newFileNames[0], 1) + Click.id("checklist-" + checklistUuid, wait_for_page=True) + Wait.text_by_id(Constants.Dashboard.Checklist.Name.ID, newFileNames[0]) + FEChecklist.add_next_step_updated(checklistName, newFileNames[1]) + # vALIDATE SCROLLING + actualVfNameid = "clickable-" + myVfName + actualVfName = Get.by_id(actualVfNameid, wait_for_page=True) + if actualVfName != '': + Helper.internal_assert(myVfName, actualVfName) + + @staticmethod + def validate_multi_eng(user_content, checklist_content, newEL_content, actualVfNameid): + query = "UPDATE ice_user_profile SET role_id=2 WHERE email = '" + \ + str(newEL_content['email']) + "';" + DBGeneral.update_by_query(query) + FEWizard.invite_team_members_modal(newEL_content['email']) + # Fetch one AT&T user ID. + enguuid = DBGeneral.select_where( + "uuid", "ice_engagement", "engagement_manual_id", user_content['engagement_manual_id'], 1) + invitation_token = DBUser.select_invitation_token( + "invitation_token", "ice_invitation", "engagement_uuid", enguuid, newEL_content['email'], 1) + URL = Constants.Default.InviteURL.Login.TEXT + invitation_token + FEGeneral.re_open(URL) + FEUser.login(newEL_content[ + 'email'], Constants.Default.Password.TEXT, expected_element=actualVfNameid) + Click.id(actualVfNameid, wait_for_page=True) + count = None + try: + session.ice_driver.find_element_by_id( + "checklist-" + checklist_content['uuid']) + count += 1 + except: + logger.debug( + "check list not visible for EL invited : " + str(newEL_content['email'])) + assertTrue(count == None) + query = "UPDATE ice_user_profile SET role_id=1 WHERE email = '" + \ + str(newEL_content['email']) + "';" + DBGeneral.update_by_query(query) + + @staticmethod + def create_cl_without_files(user_content): + FEOverview.click_on_vf(user_content) + Click.id("checklist-plus-" + user_content['engagement_uuid']) + Wait.id(Constants.Dashboard.Modal.CLOSE_BUTTON_ID) + checklistName = "NoAssociatedFiles" + \ + Helper.rand_string("randomString") + Enter.text_by_name("checkListName", checklistName) + Wait.xpath("//select") + if settings.DATABASE_TYPE == 'local': + Select(session.ice_driver.find_element_by_xpath("//select") + ).select_by_visible_text(Constants.Template.Heat.TEXT) + else: + Click.xpath("//select") + Click.xpath("//option[2]") + Click.id(Constants.Dashboard.LeftPanel.CreateChecklist.ID) + Wait.text_by_id(Constants.Dashboard.Checklist.Name.ID, checklistName) + + @staticmethod + def validate_audit_log(log_txt): + audit_log_list_text = Get.by_id( + Constants.Dashboard.Checklist.AuditLog.AuditLogList.ID, wait_for_page=True) + try: + log_txt in audit_log_list_text + logger.debug("validate_audit_log PASS") + except Exception as e: + errorMsg = "Failed in validate_audit_log" + raise Exception(errorMsg) + + @staticmethod + def get_to_create_new_ns_modal(): + Click.id(Constants.Dashboard.Checklist.AddNS.ID, + wait_for_page=True) + Wait.text_by_css(Constants.Dashboard.Checklist.AddNS.CSS, + Constants.Dashboard.Checklist.TITLE) + Helper.internal_assert(Constants.Dashboard.Checklist.TITLE, Get.by_css( + Constants.Dashboard.Checklist.AddNS.CSS)) + Helper.internal_assert( + Constants.Dashboard.Checklist.AddNS.TITLE, + Get.by_css(Constants.FEGeneral.CSS.H2)) + + @staticmethod + def get_to_create_new_ns_modal_via_overview(): + Click.id(Constants.Dashboard.Overview.NextSteps.Add.ID, + wait_for_page=True) + Wait.text_by_css(Constants.Dashboard.Checklist.AddNS.CSS, + Constants.Dashboard.Overview.NextSteps.Add.TITLE) + Helper.internal_assert( + Constants.Dashboard.Checklist.AddNS.TITLE, + Get.by_css(Constants.FEGeneral.CSS.H2)) + + @staticmethod + def get_jenkins_log(): + Click.id(Constants.Dashboard.Checklist.JenkinsLog.ID, True) + Wait.text_by_id( + Constants.Dashboard.Checklist.JenkinsLog.Modal.Title.ID, + Constants.Dashboard.Checklist.JenkinsLog.Modal.Title.TEXT, True) + log = Get.by_id( + Constants.Dashboard.Checklist.JenkinsLog.Modal.Body.ID, True) + Helper.assertTrue(Constants.Dashboard.Checklist.JenkinsLog.Modal.Body.TEXT_SAMPLE in log, + "Jenkins log could not be viewed.") + Click.id(Constants.Dashboard.Modal.CLOSE_BUTTON_ID) + return log + diff --git a/services/frontend/fe_checklist_template.py b/services/frontend/fe_checklist_template.py new file mode 100644 index 0000000..19e91aa --- /dev/null +++ b/services/frontend/fe_checklist_template.py @@ -0,0 +1,254 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +from selenium.webdriver.common.action_chains import ActionChains +from selenium.webdriver.common.keys import Keys + +from services.api.api_virtual_function import APIVirtualFunction +from services.constants import Constants +from services.database.db_checklist import DBChecklist +from services.database.db_user import DBUser +from services.frontend.base_actions.click import Click +from services.frontend.base_actions.enter import Enter +from services.frontend.base_actions.get import Get +from services.frontend.base_actions.wait import Wait +from services.frontend.fe_checklist import FEChecklist +from services.frontend.fe_general import FEGeneral +from services.frontend.fe_overview import FEOverview +from services.frontend.fe_user import FEUser +from services.helper import Helper +from services.logging_service import LoggingServiceFactory +from services.session import session + + +logger = LoggingServiceFactory.get_logger() + +class FEChecklistTemplate: + + @staticmethod + def basic_admin_navigation(): + FEUser.login( + Constants.Users.Admin.EMAIL, Constants.Default.Password.TEXT) + FEUser.go_to_admin() + + @staticmethod + def click_on_template_name_on_navigation(template_name, text): + Wait.text_by_name(template_name, text, wait_for_page=True) + Click.name(template_name, wait_for_page=True) + + @staticmethod + def click_on_save_and_assert_success_msg(): + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.SAVE_BTN_ID, wait_for_page=True) + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.APPROVE_BTN_ID, wait_for_page=True) + Wait.text_by_id(Constants.Dashboard.LeftPanel.EditChecklistTemplate.SUCCESS_ID, + Constants.Dashboard.LeftPanel.EditChecklistTemplate.SUCCESS_SAVE_MSG) + + @staticmethod + def click_on_disabled_save_and_assert_for_promp_msg(): + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.SAVE_BTN_ID) + session.run_negative(lambda: Click.id(Constants.Dashboard.LeftPanel.EditChecklistTemplate.APPROVE_BTN_ID), + "Ooops modal window is opened although 'Save' button should have been disabled") + + @staticmethod + def save_with_no_changes(): + Wait.text_by_id(Constants.Dashboard.LeftPanel.EditChecklistTemplate.SAVE_BTN_ID, + Constants.Dashboard.LeftPanel.EditChecklistTemplate.SAVE_BTN) + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.SAVE_BTN_ID, wait_for_page=True) + Wait.text_by_name(Constants.Dashboard.LeftPanel.EditChecklistTemplate.HEAT, + Constants.Dashboard.LeftPanel.EditChecklistTemplate.HEAT) + Wait.text_by_id(Constants.Dashboard.LeftPanel.EditChecklistTemplate.APPROVE_BTN_TITLE_ID, + Constants.Dashboard.LeftPanel.EditChecklistTemplate.APPROVE_BTN_TITLE_TEXT) + Wait.text_by_id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.APPROVE_BTN_ID, "Yes") + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.APPROVE_BTN_ID, wait_for_page=True) + Wait.text_by_id(Constants.Dashboard.LeftPanel.EditChecklistTemplate.SUCCESS_ID, + Constants.Dashboard.LeftPanel.EditChecklistTemplate.CL_TEMPLATE_SAVED_TXT) + + @staticmethod + def discard_checklist_after_modification(): + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.FIRST_SECTION_ID, wait_for_page=True) + Enter.text_by_id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.FIRST_SECTION_INPUT_ID, "ttttttt", wait_for_page=True) + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.FIRST_SECTION_ID) + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.REJECT_BTN_ID) + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.APPROVE_BTN_ID, wait_for_page=True) + Wait.text_by_id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.SUCCESS_ID, "All changes discarded.") + + @staticmethod + def edit_template_and_save(): + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.FIRST_SECTION_ID) + Enter.text_by_id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.FIRST_SECTION_INPUT_ID, "Ros Is My Mentor") + FEChecklistTemplate.click_on_save_and_assert_success_msg() + + @staticmethod + def del_lineitem_and_save(): + Click.id(Constants.Dashboard.LeftPanel.EditChecklistTemplate.FIRST_SECTION_ID, wait_for_page=True) + Enter.text_by_id(Constants.Dashboard.LeftPanel.EditChecklistTemplate.FIRST_SECTION_INPUT_ID, + "Ros Is My Mentor", wait_for_page=True) + Click.id(Constants.Dashboard.LeftPanel.EditChecklistTemplate.FIRST_SECTION_ID) + FEChecklistTemplate.click_on_save_and_assert_success_msg() + + @staticmethod + def add_lineitem_and_save(): + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.ADD_LINE_ITEM_BTN, wait_for_page=True) + Click.xpath("//li[@id='select-lineitem-btn-0.1']/span[2]") + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.EDIT_LINE_ITEM_BTN) + Enter.text_by_id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.EDIT_LINE_ITEM_NAME, "xxx") + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.EDIT_LINE_ITEM_BTN, wait_for_page=True) + FEChecklistTemplate.click_on_save_and_assert_success_msg() + + @staticmethod + def edit_description_lineitem_and_save(): + isBold = False + desc = Helper.rand_string("randomString") + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.FIRST_LINE_ITEM_ID) + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.EDIT_LINE_ITEM_BTN) + Enter.text_by_id(Constants.Dashboard.LeftPanel.EditChecklistTemplate.EDIT_LINE_ITEM_NAME, + Helper.rand_string("randomString")) + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.EDIT_LINE_ITEM_DESC) + editor_element = Get.wysiwyg_element_by_id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.LINE_ITEM_DESC_TEXT_BOX) + editor_element.clear() + editor_element.send_keys(desc) + Wait.page_has_loaded() + actionChains = ActionChains(session.ice_driver) + actionChains.double_click(editor_element).perform() + Wait.page_has_loaded() + Click.xpath( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.WYSIWYG_BUTTON_BOLD) + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.EDIT_LINE_ITEM_BTN, wait_for_page=True) + isBold = Wait.is_css_exists("b") + while not isBold: + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.EDIT_LINE_ITEM_BTN, wait_for_page=True) + actionChains.double_click(editor_element).perform() + Click.xpath( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.WYSIWYG_BUTTON_BOLD, wait_for_page=True) + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.EDIT_LINE_ITEM_BTN, wait_for_page=True) + isBold = Wait.is_css_exists("b") + if isBold: + FEChecklistTemplate.click_on_save_and_assert_success_msg() + FEGeneral.refresh() + Click.name( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.HEAT, wait_for_page=True) + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.FIRST_LINE_ITEM_ID, wait_for_page=True) + Wait.css("b") + Wait.text_by_css("b", desc, wait_for_page=True) + + @staticmethod + def rollback_add_lineitem_and_save(): + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.DELETE_LINE_ITEM) + FEChecklistTemplate.click_on_save_and_assert_success_msg() + FEChecklistTemplate.rollback_to_heat_teampleate() + + @staticmethod + def add_lineitem_and_check_db(): + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.FIRST_SECTION_ID) + Enter.text_by_id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.FIRST_SECTION_INPUT_ID, "Ros Is My Mentor") + FEChecklistTemplate.click_on_save_and_assert_success_msg() + result = DBChecklist.checkChecklistIsUpdated() + Helper.internal_not_equal(result, None) + + @staticmethod + def check_cl_after_lineitem_added(): + template_name = Constants.Dashboard.LeftPanel.EditChecklistTemplate.HEAT + user_content = APIVirtualFunction.create_engagement() + FEUser.login( + Constants.Users.Admin.EMAIL, Constants.Default.Password.TEXT) + vfName = user_content['vfName'] + engagement_id = DBChecklist.fetchEngByVfName(vfName) + engLeadEmail = DBUser.select_el_email(vfName) + engagement_manual_id = DBChecklist.fetchEngManIdByEngUuid( + engagement_id) + myVfName = engagement_manual_id + ": " + vfName + FEOverview.click_on_vf(user_content) + FEGeneral.re_open(Constants.Default.LoginURL.TEXT) + FEUser.login( + engLeadEmail, Constants.Default.Password.TEXT, engagement_manual_id) + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.DASHBOARD_ID) + Enter.text_by_id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.SEARCH_ENG_ID, vfName) + Click.id("test_" + vfName) + checklistName = FEChecklist.create_checklist( + engagement_id, vfName, None, engagement_manual_id) + FEUser.go_to_admin() + result = DBChecklist.fetchChecklistByName(checklistName) + FEUser.go_to_admin() + FEChecklistTemplate.click_on_template_name_on_navigation( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.HEAT, template_name) + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.EDIT_LINE_ITEM_BTN) + Enter.text_by_id(Constants.Dashboard.LeftPanel.EditChecklistTemplate.EDIT_LINE_ITEM_NAME, + "test_lineitem_added_and_audit_log_on_dupl_cl-NAME") + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.EDIT_LINE_ITEM_BTN) + FEChecklistTemplate.click_on_save_and_assert_success_msg() + Click.id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.DASHBOARD_ID) + Enter.text_by_id( + Constants.Dashboard.LeftPanel.EditChecklistTemplate.SEARCH_ENG_ID, vfName) + Click.id("test_" + vfName) + Click.id("checklist-" + str(result)) + Helper.internal_assert( + "1. automation", session.ice_driver.find_element_by_xpath("//li[@id='']").text) diff --git a/services/frontend/fe_cms.py b/services/frontend/fe_cms.py new file mode 100644 index 0000000..a86626e --- /dev/null +++ b/services/frontend/fe_cms.py @@ -0,0 +1,157 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +from services.constants import Constants +from services.database.db_cms import DBCMS +from services.frontend.base_actions.click import Click +from services.frontend.base_actions.enter import Enter +from services.frontend.base_actions.wait import Wait +from services.frontend.fe_dashboard import FEDashboard +from services.frontend.fe_general import FEGeneral +from services.frontend.fe_user import FEUser +from services.logging_service import LoggingServiceFactory +from services.session import session + + +logger = LoggingServiceFactory.get_logger() + +class FECms: + + @staticmethod + def validate_5_last_announcement_displayed(listOfTitleAnDescriptions, user_content, last_title): + last_description = listOfTitleAnDescriptions[ + len(listOfTitleAnDescriptions) - 1][1] + Wait.text_by_id(Constants.Toast.CMS_ID, last_title + ".") + FEDashboard.open_announcement() + Wait.text_by_id(Constants.Cms.Toast_title_id, last_title) + Wait.text_by_id(Constants.Cms.Toast_description, last_description) + DBCMS.update_X_days_back_post(last_title, xdays=3) + Click.id(Constants.Cms.Test_addDT_close_modal_button) + FEUser.logout() + # Validate Announcement TOAST not displayed + FEUser.login(user_content['email'], Constants.Default.Password.TEXT) + session.run_negative(lambda: Wait.text_by_id(Constants.Cms.Toast_title_id, last_title), + "Last Announcement displayed in News & Announcements sections %s" % last_title) + + @staticmethod + def validate_grandchild_page(parent_title, child_title, grand_child_title, description): + Click.id(Constants.Cms.Documentation) + Click.id(parent_title) + Click.id(child_title) + Click.id(grand_child_title) + Wait.text_by_id("center-" + grand_child_title, grand_child_title) + page_id = DBCMS.get_last_inserted_page_id() + Wait.text_by_id(page_id, description) + + @staticmethod + def announcement_validate_toast(title, description, user_content): + Wait.text_by_id(Constants.Toast.CMS_ID, title + ".") + FEDashboard.open_announcement() + Wait.text_by_id(Constants.Cms.Toast_title_id, title) + Wait.text_by_id(Constants.Cms.Toast_description, description) + Click.id(Constants.Cms.Test_addDT_close_modal_button) + Click.css("button.close") + FEUser.logout() + FEUser.login(user_content['email'], Constants.Default.Password.TEXT) + # Validate Announcement displayed in News & Announcements sections + session.run_negative(lambda: FEDashboard.open_announcement( + ), "Announcement toast disappear after 2 days %s" % title) + Wait.text_by_id(title, title) + Wait.text_by_id(description, description) + + @staticmethod + def search_documentation_title(title, user_content): + FEDashboard.open_documentation(title) + Wait.text_by_id(title, title) + logger.debug("Search Documentation by title") + Enter.text_by_id(Constants.Cms.SearchDocumentation, title, wait_for_page=True) + Wait.text_by_id(title, title) + Click.id(title, wait_for_page=True) + Wait.text_by_id(title, title) + logger.debug("Documentation found (searched by title)") + + @staticmethod + def search_documentation_content(title, content): + FEDashboard.open_documentation(title) + Wait.text_by_id(title, title) + logger.debug("Search Documentation by content") + Enter.text_by_id(Constants.Cms.SearchDocumentation, content, wait_for_page=True) + Wait.text_by_id(title, title) + Click.id(title, wait_for_page=True) + Wait.text_by_css(Constants.Cms.DocumentationPageContent, content) + logger.debug("Documentation found (searched by content)") + + @staticmethod + def validate_expired_post_Announcement(title, description): + Wait.text_by_id(Constants.Toast.CMS_ID, title + ".") + FEDashboard.open_announcement() + Wait.text_by_id(Constants.Cms.Toast_title_id, title) + Wait.text_by_id(Constants.Cms.Toast_description, description) + DBCMS.update_X_days_back_post(title, xdays=3) + Click.id(Constants.Cms.Test_addDT_close_modal_button) + FEGeneral.refresh() + session.run_negative(lambda: Wait.text_by_id( + Constants.Toast.CMS_ID, title + "."), "Announcement toast not disappear after 2 days %s" % title) + + @staticmethod + def validate_page(title, description): + Click.id(Constants.Cms.Documentation) + Click.id(title) + Wait.text_by_id("center-" + title, title) + page_id = DBCMS.get_last_inserted_page_id() + Wait.text_by_id(page_id, description) + + @staticmethod + def validate_FAQ(description): + Wait.text_by_id(Constants.Cms.Tooltip_title, "Did you know?") + Wait.text_by_id(Constants.Cms.Tooltip_description, description) + + @staticmethod + def validate_news(title, description): + Wait.text_by_id(title, title) + Wait.text_by_id(description, description) + Click.id(title) + Wait.text_by_id(Constants.Cms.Toast_title_id, title) + Wait.text_by_id(Constants.Cms.Toast_description, description) + + @staticmethod + def validae_announcement(title, description): + Wait.text_by_id(Constants.Toast.CMS_ID, title + ".") + FEDashboard.open_announcement() + Wait.text_by_id(Constants.Cms.Toast_title_id, title) + Wait.text_by_id(Constants.Cms.Toast_description, description) diff --git a/services/frontend/fe_dashboard.py b/services/frontend/fe_dashboard.py new file mode 100644 index 0000000..0df66d4 --- /dev/null +++ b/services/frontend/fe_dashboard.py @@ -0,0 +1,289 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +from selenium.webdriver.support.ui import Select + +from services.constants import Constants +from services.database.db_user import DBUser +from services.frontend.base_actions.click import Click +from services.frontend.base_actions.enter import Enter +from services.frontend.base_actions.get import Get +from services.frontend.base_actions.wait import Wait +from services.frontend.fe_general import FEGeneral +from services.frontend.fe_overview import FEOverview +from services.frontend.fe_user import FEUser +from services.helper import Helper +from services.logging_service import LoggingServiceFactory +from services.session import session + + +logger = LoggingServiceFactory.get_logger() + + +class FEDashboard: + + @staticmethod + def open_announcement(): + try: + Click.id("read-more-button") + except Exception as e: + errorMsg = "Failed to go to Announcement page." + raise Exception(errorMsg, e) + + @staticmethod + def open_documentation(title): + try: + Click.id("documentation", wait_for_page=True) + Wait.id("search-doc") + Wait.text_by_id(title, title, wait_for_page=True) + except Exception as e: + errorMsg = "Failed to go to Announcement page." + raise Exception(errorMsg, e) + + @staticmethod + def validate_filtering_by_stage(user_content, stage): + FEGeneral.re_open(Constants.Default.LoginURL.TEXT) + # Validate Scrolling # + FEUser.login(user_content['el_email'], Constants.Default.Password.TEXT) + FEOverview.click_on_vf(user_content) + Click.id(Constants.Dashboard.Statuses.ID, wait_for_page=True) + Wait.text_by_id("dashboard-title", "Statuses", wait_for_page=True) + Wait.id("search-filter-stage") + Select(session.ice_driver.find_element_by_id( + "search-filter-stage")).select_by_visible_text(stage) + Wait.id( + Constants.Dashboard.Statuses.ExportExcel.ID, wait_for_page=True) + engLeadID = DBUser.select_user_native_id(user_content['el_email']) + # Query for fetching count of rows per stage. + countOfEngInStagePerUser = DBUser.select_user_engagements_by_stage( + stage, engLeadID) + # Calculate number of pages # + NUM_OF_RESULTS_PER_PAGES = 8 + number_of_pages = countOfEngInStagePerUser // NUM_OF_RESULTS_PER_PAGES + logger.debug("Number of pages: " + str(number_of_pages)) + if (countOfEngInStagePerUser % NUM_OF_RESULTS_PER_PAGES != 0): + number_of_pages += 1 + logger.debug("number_of_pages " + str(number_of_pages)) # Scroll # + Wait.id("engagements-pagination", wait_for_page=True) + element = session.ice_driver.find_element_by_id( + "engagements-pagination") + element.location_once_scrolled_into_view + Click.link_text(str(number_of_pages), wait_for_page=True) + + @staticmethod + def validate_filtering_by_stage_with_page_ids(user_content, stage): + FEOverview.click_on_vf(user_content) + Click.id(Constants.Dashboard.Statuses.ID) + # Stage Active Validation # + Wait.text_by_id("dashboard-title", "Statuses") + Wait.id(Constants.Dashboard.Statuses.FilterDropdown.ID) + Select(session.ice_driver.find_element_by_id( + Constants.Dashboard.Statuses.FilterDropdown.ID)).select_by_visible_text("Intake") + Wait.page_has_loaded() + Select(session.ice_driver.find_element_by_id( + Constants.Dashboard.Statuses.FilterDropdown.ID)).select_by_visible_text(stage) + Wait.id( + Constants.Dashboard.Statuses.ExportExcel.ID, wait_for_page=True) + countIdsActive = 0 + engLeadID = DBUser.select_user_native_id(user_content['el_email']) + countOfEngInStagePerUser = DBUser.select_user_engagements_by_stage( + stage, engLeadID) # Calculate number of pages # + NUM_OF_RESULTS_PER_PAGES = 8 + number_of_pages = countOfEngInStagePerUser // NUM_OF_RESULTS_PER_PAGES + if countOfEngInStagePerUser <= NUM_OF_RESULTS_PER_PAGES: + number_of_pages = 1 + if number_of_pages == 1: + # Count all engagements on current page + logger.debug("Number of pages: " + str(number_of_pages)) + ids = session.ice_driver.find_elements_by_xpath('//*[@id]') + for ii in ids: + if "starred-" in ii.get_attribute('id'): + # Print ii.tag_name (id name as string). + logger.debug(ii.get_attribute('id')) + countIdsActive += 1 + Wait.id(Constants.Dashboard.Statuses.ExportExcel.ID) + if countIdsActive == countOfEngInStagePerUser: + logger.debug("result right") + else: + if countOfEngInStagePerUser % NUM_OF_RESULTS_PER_PAGES != 0: + number_of_pages += 1 + logger.debug("number_of_pages " + str(number_of_pages)) + # Scroll # + Wait.id("engagements-pagination") + element = session.ice_driver.find_element_by_id( + "engagements-pagination") + element.location_once_scrolled_into_view + if number_of_pages > 1: + Click.link_text(str(number_of_pages), wait_for_page=True) + + @staticmethod + def validate_statistics_by_stages(user_content): + # Validate Scrolling # + FEOverview.click_on_vf(user_content) + Click.id(Constants.Dashboard.Statuses.ID) + Wait.text_by_id("dashboard-title", "Statuses") + Wait.css(Constants.Dashboard.Statuses.Statistics.FilterDropdown.CSS) + Select(session.ice_driver.find_element_by_css_selector( + Constants.Dashboard.Statuses.Statistics.FilterDropdown.CSS)).select_by_visible_text("All") + engLeadID = DBUser.select_user_native_id(user_content['el_email']) + countOfEngInStagePerUser = DBUser.select_all_user_engagements( + engLeadID) # Scroll # + Wait.text_by_id( + Constants.Dashboard.Statuses.Statistics.EngagementsNumber.ID, + str(countOfEngInStagePerUser), wait_for_page=True) + element = session.ice_driver.find_element_by_id( + Constants.Dashboard.Statuses.Statistics.EngagementsNumber.ID) + # Stage Active Validation # + element.location_once_scrolled_into_view + Wait.css( + Constants.Dashboard.Statuses.Statistics.FilterDropdown.CSS, wait_for_page=True) + Select(session.ice_driver.find_element_by_css_selector( + Constants.Dashboard.Statuses.Statistics.FilterDropdown.CSS)).select_by_visible_text("Active") + countOfEngInStagePerUser = DBUser.select_user_engagements_by_stage( + "Active", engLeadID) + Wait.text_by_id( + Constants.Dashboard.Statuses.Statistics.EngagementsNumber.ID, str(countOfEngInStagePerUser), wait_for_page=True) + + @staticmethod + def search_by_vf(user_content): + engName = user_content[ + 'engagement_manual_id'] + ": " + user_content['vfName'] + engSearchID = "eng-" + engName + FEGeneral.re_open_not_clean_cache(Constants.Default.DashbaordURL.TEXT) + logger.debug("Search engagement by engagement_manual_id") + Enter.text_by_id(Constants.Dashboard.Statuses.SearchBox.ID, + user_content['engagement_manual_id'], wait_for_page=True) + eng_manual_id = user_content['engagement_manual_id'] + ":" + Wait.text_by_id(engSearchID, eng_manual_id) + + @staticmethod + def search_in_left_searchbox_by_param(manual_id, vf_name, param): + myVfName = manual_id + ": " + vf_name + Enter.text_by_xpath( + Constants.Dashboard.LeftPanel.SearchBox.Results.XPATH, param) + Wait.text_by_css( + Constants.Dashboard.LeftPanel.SearchBox.Results.CSS, myVfName) + Click.css(Constants.Dashboard.LeftPanel.SearchBox.Results.CSS) + + @staticmethod + def check_vnf_version(user_content): + current_vnf_value = Get.by_css( + "#progress_bar_" + user_content['engagement_manual_id'] + " ." + Constants.Dashboard.Overview.Progress.VnfVersion.CLASS, wait_for_page=True) + Helper.internal_assert(current_vnf_value, user_content['vnf_version']) + + @staticmethod + def search_in_dashboard(user_content, vfcName, users): + engName = user_content[ + 'engagement_manual_id'] + ": " + user_content['vfName'] + engSearchID = "eng-" + engName + for user in users: + FEGeneral.re_open(Constants.Default.LoginURL.TEXT) + logger.debug("Login with user " + user) + FEUser.login(user, Constants.Default.Password.TEXT) + logger.debug("Search engagement by engagement_manual_id") + Enter.text_by_id( + Constants.Dashboard.Statuses.SearchBox.ID, user_content['engagement_manual_id']) + eng_manual_id = user_content['engagement_manual_id'] + ":" + Wait.text_by_id(engSearchID, eng_manual_id) + logger.debug("Engagement found (searched by engagement_manual_id)") + FEGeneral.refresh() + logger.debug("Search engagement by VF name") + # Search by VF name. + Enter.text_by_id( + Constants.Dashboard.Statuses.SearchBox.ID, user_content['vfName']) + Wait.text_by_id(engSearchID, eng_manual_id) + logger.debug("Engagement found (searched by VF name)") + FEGeneral.refresh() + logger.debug("Search engagement by VFC") + # Search by VFC. + Enter.text_by_id( + Constants.Dashboard.Statuses.SearchBox.ID, vfcName) + Wait.text_by_id(engSearchID, eng_manual_id) + logger.debug("Engagement found (searched by VFC)") + FEGeneral.refresh() + logger.debug("Negative search: search by random string") + # Search by VFC. + Enter.text_by_id(Constants.Dashboard.Statuses.SearchBox.ID, + "RND_STR_" + Helper.rand_string("randomString")) + Wait.text_by_id("search-results", "Export to Excel >>") + + @staticmethod + def check_if_the_eng_of_NS_is_the_correct_one(user_content): + logger.debug(" > Check if the engagement of NS is the correct one") + engName = user_content[ + 'engagement_manual_id'] + ": " + user_content['vfName'] + Wait.text_by_name( + user_content['engagement_manual_id'], "Engagement - " + engName) + return engName + + @staticmethod + def check_if_creator_of_NS_is_the_EL(user_content): + logger.debug( + " > Check if creator of NS is the EL " + user_content['el_name']) + if (user_content['el_name'] not in Get.by_name("creator-full-name-" + user_content['el_name'])): + logger.error("EL is not the creator of the NS according to UI.") + raise + + @staticmethod + def statuses_search_vf(engagement_manual_id, vf_name): + engName = engagement_manual_id + ": " + vf_name + # Search by VF name. + Enter.text_by_id( + Constants.Dashboard.Statuses.SearchBox.ID, vf_name, wait_for_page=True) + Wait.id("eng-" + engName, wait_for_page=True) + Click.id("eng-" + engName, wait_for_page=True) + Wait.text_by_id( + Constants.Dashboard.Overview.Title.ID, engName, wait_for_page=True) + + @staticmethod + def go_to_main_dashboard(): + Click.id(Constants.Dashboard.Statuses.ID) + + @staticmethod + def click_on_dashboard_and_validate_statistics(is_negative): + # Click.id(Constants.Dashboard.Default.DASHBOARD_ID) + Wait.page_has_loaded() + if is_negative: + session.run_negative(lambda: Wait.id( + Constants.Dashboard.Default.STATISTICS), "Negative test failed at Statistics appears") + else: + Wait.id(Constants.Dashboard.Default.STATISTICS) + + @staticmethod + def click_on_create_vf(): + Click.id(Constants.Dashboard.LeftPanel.AddEngagement.ID) diff --git a/services/frontend/fe_detailed_view.py b/services/frontend/fe_detailed_view.py new file mode 100644 index 0000000..bf9a5bf --- /dev/null +++ b/services/frontend/fe_detailed_view.py @@ -0,0 +1,359 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +import time + +from selenium.webdriver.support.ui import Select + +from services.constants import Constants +from services.database.db_general import DBGeneral +from services.frontend.base_actions.click import Click +from services.frontend.base_actions.enter import Enter +from services.frontend.base_actions.get import Get +from services.frontend.base_actions.wait import Wait +from services.frontend.fe_dashboard import FEDashboard +from services.frontend.fe_general import FEGeneral +from services.frontend.fe_user import FEUser +from services.helper import Helper +from services.logging_service import LoggingServiceFactory +from services.session import session + + +logger = LoggingServiceFactory.get_logger() + + +class FEDetailedView: + + @staticmethod + def search_vf_and_go_to_detailed_view(engagement_manual_id, vf_name): + engName = engagement_manual_id + ": " + vf_name + detailed_view_id = Constants.Dashboard.DetailedView.ID + engName + FEDashboard.statuses_search_vf(engagement_manual_id, vf_name) + Click.id(detailed_view_id, wait_for_page=True) + return detailed_view_id + + @staticmethod + def update_aic_version(): + Click.id( + Constants.Dashboard.DetailedView.ValidationDetails.PLUS, wait_for_page=True) + Wait.text_by_id(Constants.Dashboard.Modal.TITLE_ID, + Constants.Dashboard.DetailedView.ValidationDetails.TITLE, wait_for_page=True) + Select(session.ice_driver.find_element_by_id(Constants.Dashboard.DetailedView.AIC.Dropdown.ID) + ).select_by_visible_text(Constants.Dashboard.DetailedView.ValidationDetails.TargetAICVersion.AIC3) + Click.xpath("//option[3]", wait_for_page=True) + Click.id( + Constants.Dashboard.DetailedView.ValidationDetails.SAVE, wait_for_page=True) + + @staticmethod + def open_validation_details(): + Click.id( + Constants.Dashboard.DetailedView.ValidationDetails.PLUS, wait_for_page=True) + Wait.text_by_id(Constants.Dashboard.Modal.TITLE_ID, + Constants.Dashboard.DetailedView.ValidationDetails.TITLE, wait_for_page=True) + + @staticmethod + def save_validation_details(): + Click.id( + Constants.Dashboard.DetailedView.ValidationDetails.SAVE, wait_for_page=True) + + @staticmethod + def update_target_lab_entry(): + Click.id( + Constants.Dashboard.DetailedView.TargetLabEntry.CHANGE, wait_for_page=True) + Enter.date_picker( + '#lab-entry-date', 'vm.targetLabDate', wait_for_page=True) + Click.css( + Constants.Dashboard.DetailedView.TargetLabEntry.INPUT_CSS, wait_for_page=True) + Click.css(Constants.SubmitButton.CSS, wait_for_page=True) + actualDate = Get.by_css( + Constants.Dashboard.DetailedView.TargetLabEntry.CONTENT_CSS, wait_for_page=True) + return str(actualDate) + + @staticmethod + def validate_target_lab_entry(date): + Wait.text_by_css(Constants.Dashboard.DetailedView.TargetLabEntry.CSS, + Constants.Dashboard.DetailedView.TargetLabEntry.TEXT, wait_for_page=True) + actualDate = Get.by_css( + Constants.Dashboard.DetailedView.TargetLabEntry.CONTENT_CSS) + Helper.internal_assert(actualDate, date) + + @staticmethod + def update_ecomp_release(EcompName): + count = 0 + try: + Click.id(Constants.Dashboard.DetailedView.ValidationDetails.PLUS) + Wait.text_by_id(Constants.Dashboard.Modal.TITLE_ID, + Constants.Dashboard.DetailedView.ValidationDetails.TITLE, wait_for_page=True) + Click.id( + Constants.Dashboard.DetailedView.ECOMP.Dropdown.ID, wait_for_page=True) + Select(session.ice_driver.find_element_by_id( + Constants.Dashboard.DetailedView.ECOMP.Dropdown.ID)).select_by_visible_text(EcompName) + Click.id(Constants.Dashboard.DetailedView.ValidationDetails.ECOMPRelease.ID_ECOMP + + EcompName, wait_for_page=True) + count += 1 + Wait.id(Constants.Dashboard.DetailedView.ValidationDetails.ECOMPRelease.ID_ECOMP + + Constants.Dashboard.DetailedView.ValidationDetails.ECOMPRelease.UNKNOW, wait_for_page=True) + Select(session.ice_driver.find_element_by_id(Constants.Dashboard.DetailedView.ECOMP.Dropdown.ID) + ).select_by_visible_text(Constants.Dashboard.DetailedView.ValidationDetails.ECOMPRelease.UNKNOW) + Click.id(Constants.Dashboard.DetailedView.ValidationDetails.ECOMPRelease.ID_ECOMP + + Constants.Dashboard.DetailedView.ValidationDetails.ECOMPRelease.UNKNOW, wait_for_page=True) + count += 1 + Click.id( + Constants.Dashboard.DetailedView.ValidationDetails.SAVE, wait_for_page=True) + Helper.internal_assert(count, 2) + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "Failed in update_ecomp_release ." + raise Exception(errorMsg) + + @staticmethod + def update_vf_version(): + try: + Click.id( + Constants.Dashboard.DetailedView.ValidationDetails.PLUS, wait_for_page=True) + Wait.text_by_id(Constants.Dashboard.Modal.TITLE_ID, + Constants.Dashboard.DetailedView.ValidationDetails.TITLE, wait_for_page=True) + newVFVersionName = "newVFVersionName-" + \ + Helper.rand_string("randomString") + Click.id( + Constants.Dashboard.DetailedView.ValidationDetails.VFVersion.ID_VERSION) + Enter.text_by_id( + Constants.Dashboard.DetailedView.ValidationDetails.VFVersion.ID_VERSION, newVFVersionName, wait_for_page=True) + Click.id( + Constants.Dashboard.DetailedView.ValidationDetails.SAVE, wait_for_page=True) + return newVFVersionName + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "Failed in update_ecomp_release ." + raise Exception(errorMsg) + + @staticmethod + def validate_aic_version(): + FEGeneral.refresh() + Wait.id( + Constants.Dashboard.DetailedView.AIC.ID + "3.0", wait_for_page=True) + + @staticmethod + def validate_ecomp_version(): + FEGeneral.refresh() + Wait.id(Constants.Dashboard.DetailedView.ECOMP.ID + + Constants.Dashboard.DetailedView.ValidationDetails.ECOMPRelease.UNKNOW, wait_for_page=True) + + @staticmethod + def validate_vf_version(newVFVersionName): + FEGeneral.refresh() + Wait.id(Constants.Dashboard.DetailedView.ValidationDetails.VFVersion.VF_VERSION_ID + + newVFVersionName, wait_for_page=True) + + @staticmethod + def validate_all_titles_on_dv_form(): + Wait.text_by_id(Constants.Dashboard.DetailedView.DeploymentTarget.ID, + Constants.Dashboard.DetailedView.DeploymentTarget.TEXT, wait_for_page=True) + Wait.text_by_id(Constants.Dashboard.DetailedView.VirtualFunctionComponents.ID, + Constants.Dashboard.DetailedView.VirtualFunctionComponents.TEXT) + Wait.text_by_id(Constants.Dashboard.DetailedView.TargetLabEntry.ID, + Constants.Dashboard.DetailedView.TargetLabEntry.TEXT) + Wait.text_by_id(Constants.Dashboard.DetailedView.ValidationDetails.ID, + Constants.Dashboard.DetailedView.ValidationDetails.TEXT) + Wait.text_by_id(Constants.Dashboard.DetailedView.ValidationDetails.TargetAICVersion.ID, + Constants.Dashboard.DetailedView.ValidationDetails.TargetAICVersion.TEXT) + Wait.text_by_id(Constants.Dashboard.DetailedView.ValidationDetails.ECOMPRelease.ID, + Constants.Dashboard.DetailedView.ValidationDetails.ECOMPRelease.TEXT) + Wait.text_by_id(Constants.Dashboard.DetailedView.ValidationDetails.VFVersion.ID, + Constants.Dashboard.DetailedView.ValidationDetails.VFVersion.TEXT, wait_for_page=True) + + @staticmethod + def add_deployment_target(user_content): + Click.id(Constants.Dashboard.DetailedView.TargetLabEntry.Add.ID) + Wait.text_by_id(Constants.Dashboard.Modal.TITLE_ID, + Constants.Dashboard.DetailedView.DeploymentTarget.TITLE) + # FIXME: empty drop-down, tests will fail. + Select(session.ice_driver.find_element_by_xpath( + "//select")).select_by_visible_text("Lisle (DPA3)") + Click.id( + Constants.Dashboard.DetailedView.DeploymentTarget.SAVE, wait_for_page=True) + Wait.text_by_css( + Constants.Dashboard.DetailedView.DeploymentTarget.CSS, "Lisle (DPA3)", wait_for_page=True) + Wait.text_by_id(Constants.Dashboard.DetailedView.AIC.ID + + user_content['target_aic'], user_content['target_aic']) + e2edate = FEGeneral.date_short_formatter() + Wait.text_by_css( + Constants.Dashboard.DetailedView.TargetLabEntry.CONTENT_CSS, e2edate) + + @staticmethod + def remove_deployment_target(user_content): + Wait.text_by_id( + "visible-dts-Lisle (DPA3)", "Lisle (DPA3)", wait_for_page=True) + dt_site_id = DBGeneral.select_query( + "SELECT uuid FROM public.ice_deployment_target_site where name = 'Lisle (DPA3)'") + Click.id("visible-dts-Lisle (DPA3)") + Wait.id( + Constants.Dashboard.DetailedView.DeploymentTarget.ID_REMOVE_DTS + dt_site_id) + Click.id(Constants.Dashboard.DetailedView.DeploymentTarget.ID_REMOVE_DTS + + dt_site_id, wait_for_page=True) + session.run_negative(lambda: Wait.text_by_id( + "visible-dts-Lisle (DPA3)", "Lisle (DPA3)", wait_for_page=True), "Negative test failed at wait text Lisle (DPA3)") + + @staticmethod + def add_vfc(): + vfcName = "VFC-" + Helper.rand_string("randomString") + Click.id(Constants.Dashboard.DetailedView.VFC.Add.ID) + Enter.text_by_name("name", vfcName) + session.ice_driver.find_element_by_name("extRefID").click() + Enter.text_by_name("extRefID", Helper.rand_string("randomNumber")) + Select(session.ice_driver.find_element_by_id( + Constants.Dashboard.DetailedView.VFC.Choose_Company.ID)).select_by_visible_text("AT&T") + Click.id(Constants.Dashboard.DetailedView.VFC.Save_button.ID) + return vfcName + + @staticmethod + def add_vfcs(name, extRefID): + Click.id( + Constants.Dashboard.DetailedView.VFC.Add.ID, wait_for_page=True) + Wait.text_by_id(Constants.Dashboard.Modal.TITLE_ID, + "Add Virtual Function Components (VFCs)") + Enter.text_by_name("name", name) + Click.name("extRefID", wait_for_page=True) + Enter.text_by_name("extRefID", extRefID, wait_for_page=True) + Select(session.ice_driver.find_element_by_id( + Constants.Dashboard.DetailedView.VFC.Choose_Company.ID)).select_by_visible_text("Amdocs") + Wait.text_by_css("span.add-text", "Add VFC", wait_for_page=True) + Click.css("span.add-text", wait_for_page=True) + logger.debug("Add VFC no.2") + Enter.text_by_xpath( + "//div[2]/ng-form/div/input", "djoni2", wait_for_page=True) + Enter.text_by_xpath("//div[2]/ng-form/div[2]/input", "loka2") + Enter.text_by_xpath("//div[2]/ng-form/div[4]/input", "companyManual2") + Click.id( + Constants.Dashboard.DetailedView.VFC.Save_button.ID, wait_for_page=True) + + @staticmethod + def remove_vfc(user_content): + vf_id = DBGeneral.select_where( + "uuid", "ice_vf", "name", user_content['vfName'], 1) + djoni_uuid = None + counter = 0 + while not djoni_uuid and counter <= Constants.DBConstants.RETRIES_NUMBER: + time.sleep(session.wait_until_time_pause_long) + djoni_uuid = DBGeneral.select_where_and( + "uuid", "ice_vfc", "vf_id", vf_id, "name", "djoni", 1) + logger.debug("Checklist state not changed yet (%s of %s)" % ( + counter, Constants.DBConstants.RETRIES_NUMBER)) + counter += 1 + logger.debug("VFC_UUID was successfully selecteded : " + + djoni_uuid + ", and was verified over the DB") + Wait.text_by_id(Constants.Dashboard.DetailedView.VFC.ID + + "djoni", "djoni (loka)", wait_for_page=True) + Wait.text_by_id(Constants.Dashboard.DetailedView.VFC.ID + + "djoni2", "djoni2 (loka2)", wait_for_page=True) + Click.id( + Constants.Dashboard.DetailedView.VFC.ID + "djoni", wait_for_page=True) + Click.id(Constants.Dashboard.DetailedView.VFC.Remove.ID + + djoni_uuid, wait_for_page=True) + + @staticmethod + def validate_deployment_targets(user_content, users): + for user in users: + FEGeneral.re_open(Constants.Default.LoginURL.TEXT) + logger.debug("Login with user " + user) + FEUser.login(user, Constants.Default.Password.TEXT) + FEDetailedView.search_vf_and_go_to_detailed_view( + user_content['engagement_manual_id'], user_content['vfName']) + Wait.id( + Constants.Dashboard.DetailedView.DeploymentTarget.AddDeploymentTargetButton.ID) + + @staticmethod + def add_remove_deployment_targets(user_content, users): + for user in users: + FEGeneral.re_open(Constants.Default.LoginURL.TEXT) + logger.debug("Login with user " + user) + FEUser.login(user, Constants.Default.Password.TEXT) + FEDetailedView.search_vf_and_go_to_detailed_view( + user_content['engagement_manual_id'], user_content['vfName']) + FEDetailedView.add_deployment_target(user_content) + FEDetailedView.remove_deployment_target(user_content) + + @staticmethod + def validate_negative_role_for_deployment_targets(user_content, users): + for user in users: + FEGeneral.re_open(Constants.Default.LoginURL.TEXT) + logger.debug("Login with user " + user) + FEUser.login(user, Constants.Default.Password.TEXT) + FEDetailedView.search_vf_and_go_to_detailed_view( + user_content['engagement_manual_id'], user_content['vfName']) + session.run_negative(lambda: Click.id(Constants.Dashboard.DetailedView.DeploymentTarget.AddDeploymentTargetButton.ID), + "Negative test failed at click_on_ deployment-targets with user %s" % user) + + @staticmethod + def click_on_update_aic_version(): + Click.id( + Constants.Dashboard.DetailedView.ValidationDetails.PLUS, wait_for_page=True) + Wait.text_by_id(Constants.Dashboard.Modal.TITLE_ID, + Constants.Dashboard.DetailedView.ValidationDetails.TITLE, wait_for_page=True) + + @staticmethod + def click_on_update_ecomp_release(): + Click.id( + Constants.Dashboard.DetailedView.ValidationDetails.PLUS, wait_for_page=True) + Wait.text_by_id(Constants.Dashboard.Modal.TITLE_ID, + Constants.Dashboard.DetailedView.ValidationDetails.TITLE, wait_for_page=True) + + @staticmethod + def select_aic_version_from_list(aic_version): + Select(session.ice_driver.find_element_by_id( + Constants.Dashboard.DetailedView.AIC.Dropdown.ID)).select_by_visible_text(aic_version) + + @staticmethod + def compare_aic_selected_version(expected_aic_version): + Helper.internal_assert(Get.by_id( + Constants.Dashboard.DetailedView.AIC.ID + expected_aic_version), expected_aic_version) + + @staticmethod + def compare_selected_ecomp_release(expected_ecomp_release): + Helper.internal_assert(Get.by_id( + Constants.Dashboard.DetailedView.ECOMP.ID + expected_ecomp_release), expected_ecomp_release) + + @staticmethod + def validate_deprecated_aic_version_in_dropdown(expected_aic_version): + Helper.internal_assert(Get.by_id(Constants.Dashboard.DetailedView.AIC.Dropdown.UniversalVersion.ID % + expected_aic_version), "AIC " + expected_aic_version + " - Deprecated") + + @staticmethod + def validate_deprecated_ecomp_release_in_dropdown(expected_ecomp_release): + Helper.internal_assert(Get.by_id(Constants.Dashboard.DetailedView.ECOMP.Dropdown.UniversalRelease.ID % + expected_ecomp_release), expected_ecomp_release + " - Deprecated") diff --git a/services/frontend/fe_general.py b/services/frontend/fe_general.py new file mode 100644 index 0000000..c6832cb --- /dev/null +++ b/services/frontend/fe_general.py @@ -0,0 +1,261 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +import json +import time + +from django.conf import settings +from selenium.webdriver.support.select import Select + +from services.constants import Constants +from services.frontend.base_actions.click import Click +from services.frontend.base_actions.enter import Enter +from services.frontend.base_actions.get import Get +from services.frontend.base_actions.wait import Wait +from services.helper import Helper +from services.logging_service import LoggingServiceFactory +from services.session import session + + +logger = LoggingServiceFactory.get_logger() + +class FEGeneral(Helper): + + @staticmethod + def date_formatter(): + d = int(time.strftime("%d")) + if (d == 1 or d == 21 or d == 31): + d = str(d) + "st" + elif (d == 2 or d == 22): + d = str(d) + "nd" + elif (d == 3 or d == 23): + d = str(d) + "rd" + else: + d = str(d) + "th" + return time.strftime("%A %B " + d + " %Y") + + @staticmethod + def date_short_formatter(): + return time.strftime("%-m" + "/" + "%-d" + "/" + "%y") + + @staticmethod + def re_open(reopen_url): + try: + logger.debug("Reopen URL: " + reopen_url) + session.ice_driver.get('javascript:localStorage.clear();') + session.ice_driver.get('javascript:sessionStorage.clear();') + session.ice_driver.delete_all_cookies() + # Open FireFox with requested URL. + session.ice_driver.get("about:blank") + # Open FireFox with requested URL. + session.ice_driver.get(reopen_url) + session.ice_driver.maximize_window() + Wait.page_has_loaded() + except Exception as e: + errorMsg = "Could not reopen requested page" + raise Exception(errorMsg, reopen_url) + + @staticmethod + def re_open_not_clean_cache(url): + try: + # Open FireFox with requested URL. + session.ice_driver.get(url) + session.ice_driver.maximize_window() + except: + errorMsg = "Could not reopen requested page" + raise Exception(errorMsg, url) + logger.debug("Moving to next test case") + + @staticmethod + def refresh(): + try: # Click on element in UI, by CSS locator. + session.ice_driver.refresh() + Wait.page_has_loaded() + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "Could not refresh the page." + logger.error(errorMsg) + raise Exception(errorMsg, e) + + @staticmethod + def select_vendor_from_list(vendor): + Wait.name(Constants.Signup.Company.NAME) + Select(session.ice_driver.find_element_by_name( + Constants.Signup.Company.NAME)).select_by_visible_text(vendor) + + @staticmethod + def go_to_signup_from_login(): + Click.link_text(Constants.Login.Signup.LINK_TEXT, wait_for_page=True) + Wait.text_by_css( + Constants.Signup.Title.CSS, Constants.Signup.Title.TEXT, wait_for_page=True) + + @staticmethod + def form_enter_name(name): + Enter.text_by_name(Constants.Signup.FullName.NAME, name) + + @staticmethod + def form_enter_email(email): + Enter.text_by_name(Constants.Signup.Email.NAME, email) + + @staticmethod + def form_enter_phone(phone): + Enter.text_by_name(Constants.Signup.Phone.NAME, phone) + + @staticmethod + def form_enter_password(password): + Enter.text_by_name(Constants.Signup.Password.NAME, password) + + @staticmethod + def form_check_checkbox(xpath): + Click.xpath(xpath) + + @staticmethod + def click_on_submit(): + Click.css(Constants.SubmitButton.CSS) + + @staticmethod + def go_to_login_from_signup(): + Click.link_text(Constants.Signup.HaveAccount.LINK_TEXT) + Wait.text_by_css(Constants.Login.Title.CSS, Constants.Login.Title.TEXT) + + @staticmethod + def verify_toast_message(expected_message): + Wait.text_by_id( + Constants.Toast.ID, expected_message, wait_for_page=True) + + @staticmethod + def form_validate_name(name): + name_in_ui = Get.value_by_name( + Constants.Dashboard.Avatar.Account.FullName.NAME) + Helper.internal_assert(name, name_in_ui) + + @staticmethod + def form_validate_email(email): + email_in_ui = Get.value_by_name( + Constants.Dashboard.Avatar.Account.Email.NAME) + Helper.internal_assert(email, email_in_ui) + + @staticmethod + def form_validate_phone(phone): + phone_in_ui = Get.value_by_name( + Constants.Dashboard.Avatar.Account.Phone.NAME) + Helper.internal_assert(phone, phone_in_ui) + + @staticmethod + def form_validate_company(company): + company_in_ui = Get.value_by_name( + Constants.Dashboard.Avatar.Account.Company.NAME) + Helper.internal_assert(company, company_in_ui) + + @staticmethod + def form_validate_ssh(key): + key_in_ui = Get.value_by_name( + Constants.Dashboard.Avatar.Account.SSHKey.NAME) + Helper.internal_assert(key, key_in_ui) + + @staticmethod + def go_to_reset_password_from_login(): + Click.link_text(Constants.Login.ResetPassword.LINK_TEXT) + + @staticmethod + def send_reset_password(email): + FEGeneral.go_to_reset_password_from_login() + Wait.text_by_css( + Constants.ResetPassword.Title.CSS, Constants.ResetPassword.Title.TEXT) + Enter.text_by_name(Constants.ResetPassword.Email.NAME, email) + Wait.text_by_css( + Constants.SubmitButton.CSS, Constants.ResetPassword.Button.TEXT) + Click.css(Constants.SubmitButton.CSS) + Wait.text_by_id( + Constants.Toast.ID, Constants.ResetPassword.Toast.Success.TEXT) + logger.debug(Constants.ResetPassword.Toast.Success.TEXT) + + @staticmethod + def verify_home_elements(): + Wait.text_by_id(Constants.Home.Title.ID, Constants.Home.Title.TEXT) + element = session.ice_driver.find_element_by_id( + Constants.Home.Collaborate.ID) + element.location_once_scrolled_into_view + Wait.text_by_xpath( + Constants.Home.Collaborate.XPATH, Constants.Home.Collaborate.TEXT) + Wait.text_by_xpath( + Constants.Home.Validate.XPATH, Constants.Home.Validate.TEXT) + Wait.text_by_xpath( + Constants.Home.Incubate.XPATH, Constants.Home.Incubate.TEXT) + element = session.ice_driver.find_element_by_id(Constants.Home.Logo.ID) + element.location_once_scrolled_into_view + Wait.text_by_id(Constants.Home.Title.ID, Constants.Home.Title.TEXT) + + @staticmethod + def go_to_signup_from_homepage(): + Click.link_text(Constants.Home.GetStarted.LINK_TEXT) + Wait.text_by_css( + Constants.Signup.Title.CSS, Constants.Signup.Title.TEXT) + + @staticmethod + def get_meta_order_of_element(element_id): + return Get.meta_order_by_id(element_id) + + @staticmethod + def verify_num_of_existing_ids(requested_num_of_ids, id_prefix): + existing_id_objects_in_page = 0 + ids = session.ice_driver.find_elements_by_xpath('//*[@id]') + for id in ids: + if id_prefix in id.get_attribute('id'): + # Print id.tag_name (id name as string). + logger.debug(id.get_attribute('id')) + existing_id_objects_in_page += 1 + Helper.internal_assert( + existing_id_objects_in_page, requested_num_of_ids) + logger.debug("verify_num_of_existing_ids succeeded") + + @staticmethod + def verify_existing_files_in_list(items_list, id_to_search_for): + element = session.ice_driver.find_elements_by_id(id_to_search_for) + element_attribute_items = json.loads(element[0].get_attribute('name')) + Helper.internal_assert( + len(items_list), len(element_attribute_items) - 1) + extracted_files_list = list() + for file in element_attribute_items: + extracted_files_list.append(file['File']) + for item in items_list: + if item not in extracted_files_list: + Helper.assertTrue( + False, "%s does not exist over the client's side" % item) + logger.debug( + "verify_existing_files_in_list succeeded, All vf repo files are available for choosing.") diff --git a/services/frontend/fe_invite.py b/services/frontend/fe_invite.py new file mode 100644 index 0000000..405581c --- /dev/null +++ b/services/frontend/fe_invite.py @@ -0,0 +1,198 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +from asyncio.tasks import wait + +from selenium.webdriver.support.select import Select + +from services.api.api_user import APIUser +from services.api.api_virtual_function import APIVirtualFunction +from services.constants import Constants, ServiceProvider +from services.database.db_general import DBGeneral +from services.database.db_user import DBUser +from services.frontend.base_actions.click import Click +from services.frontend.base_actions.enter import Enter +from services.frontend.base_actions.get import Get +from services.frontend.base_actions.wait import Wait +from services.frontend.fe_general import FEGeneral +from services.frontend.fe_user import FEUser +from services.frontend.fe_wizard import FEWizard +from services.helper import Helper +from services.logging_service import LoggingServiceFactory +from services.session import session + + +logger = LoggingServiceFactory.get_logger() + +class FEInvite: + + @staticmethod + def invite_users(user_content): + engName = user_content[0][ + 'engagement_manual_id'] + ": " + user_content[0]['vfName'] + vf_left_nav_id = "clickable-" + engName + Click.id(vf_left_nav_id) + FEWizard.invite_team_members_modal(user_content[1]['email']) + # self.sleep(1) # TODO need to wait until modal window is closed. + invitation_token = DBUser.select_invitation_token("invitation_token", "ice_invitation", "engagement_uuid", + user_content[0]['engagement_uuid'], user_content[1]['email'], 1) + inviterURL = Constants.Default.InviteURL.Login.TEXT + invitation_token + FEGeneral.re_open(inviterURL) + # Login with 2nd user # + title_id = "title-id-" + engName + FEUser.login( + user_content[1]['email'], Constants.Default.Password.TEXT, title_id) + Click.id(vf_left_nav_id) + actualVfName = Get.by_id(vf_left_nav_id) + Helper.internal_assert(engName, actualVfName) + Wait.text_by_id(Constants.Dashboard.Overview.Title.ID, engName) + FEUser.logout() + return vf_left_nav_id + + @staticmethod + def invite_x_users(user_content, vf_left_nav_id, x): + for _ in range(x): # Invites 2-5 + Click.id(vf_left_nav_id) + Click.id(Constants.Dashboard.LeftPanel.AddEngagement.ID) + FEWizard.add_vf() + Click.id( + Constants.Dashboard.Wizard.CloseButton.ID, wait_for_page=True) + FEWizard.invite_team_members_modal(user_content[1]['email']) + FEGeneral.refresh() + + @staticmethod + def invite_and_validate_limit(user_content, vf_left_nav_id): + Click.id(Constants.Dashboard.LeftPanel.AddEngagement.ID) + FEWizard.add_vf() + Click.id(Constants.Dashboard.Wizard.CloseButton.ID, wait_for_page=True) + Click.id(vf_left_nav_id) + Click.id(Constants.Dashboard.Overview.TeamMember.ID) + Wait.text_by_css(Constants.Dashboard.Wizard.Title.CSS, + Constants.Dashboard.Wizard.InviteTeamMembers.Title.TEXT) + Enter.text_by_name("email", user_content[1]['email']) + Wait.text_by_css(Constants.SubmitButton.CSS, + Constants.Dashboard.Wizard.InviteTeamMembers.Button.TEXT) + Click.css(Constants.SubmitButton.CSS) + Wait.id(Constants.Toast.ID) + Helper.internal_assert( + Get.by_id(Constants.Toast.ID), "Invite couldn't be created") + + @staticmethod + def invite_x_users_from_tm(list_of_invite_emails, countofUser, countOfem, num): + Enter.text_by_name( + "email", list_of_invite_emails[countofUser], wait_for_page=True) + for _ in range(num): + try: + session.run_negative( + lambda: Click.css("span.add-icon"), "css appears") + break + except: # button exists + pass + countofUser += 1 +# Click.css("span.add-icon") + Wait.xpath("//fieldset[" + str(countOfem) + "]/div/input") + Enter.text_by_xpath( + "//fieldset[" + str(countOfem) + "]/div/input", list_of_invite_emails[countofUser]) + countOfem += 1 + Click.css(Constants.SubmitButton.CSS, wait_for_page=True) + + @staticmethod + def create_x_vfs(user_content, engName, x): + vflist = [] + FEUser.login(user_content['email'], Constants.Default.Password.TEXT) + for _ in range(x): + vf_left_nav_id = "clickable-" + engName + Click.id(vf_left_nav_id) + Click.id(Constants.Dashboard.LeftPanel.AddEngagement.ID) + vfName = FEWizard.add_vf() + vflist.append(vfName) + Click.id( + Constants.Dashboard.Wizard.CloseButton.ID, wait_for_page=True) + return vflist + + @staticmethod + def validations_for_user2(user_content, inviteEmail, vflist): + # Fetch one AT&T user ID. + engagement_id = DBGeneral.select_where( + "engagement_id", "ice_vf", "name", vflist[0], 1) + engagement_manual_id = DBGeneral.select_where( + "engagement_manual_id", "ice_engagement", "uuid", engagement_id, 1) + engLeadEmail = DBUser.select_el_email(vflist[0]) + user_content['engagement_uuid'] = engagement_id + user_content['el_email'] = engLeadEmail + uuid = DBGeneral.select_where_email( + "uuid", "ice_user_profile", user_content['email']) + sponsor = ["AT&T", 'aaaaaa', inviteEmail, '3058000000'] + invitation_token = DBUser.select_invitation_token( + "invitation_token", "ice_invitation", "engagement_uuid", engagement_id, inviteEmail, 1) + signUpURLforContact = DBUser.get_contact_signup_url( + invitation_token, uuid, sponsor[2], sponsor[1], sponsor[3], sponsor[0]) + APIUser.signup_invited_user( + sponsor[0], inviteEmail, invitation_token, signUpURLforContact, user_content, True, wait_for_gitlab=False) + activationUrl2 = DBUser.get_activation_url(sponsor[2]) + FEGeneral.re_open(activationUrl2) # Login with 2nd user # + engName = engagement_manual_id + ": " + vflist[0] + title_id = "clickable-" + engName + FEUser.login(inviteEmail, Constants.Default.Password.TEXT, title_id) + for vfName in vflist: + # Fetch one AT&T user ID. + engagement_id = DBGeneral.select_where( + "engagement_id", "ice_vf", "name", vfName, 1) + engagement_manual_id = DBGeneral.select_where( + "engagement_manual_id", "ice_engagement", "uuid", engagement_id, 1) + engName = engagement_manual_id + ": " + vfName + vf_left_nav_id = "clickable-" + engName + Click.id(vf_left_nav_id, wait_for_page=True) + + @staticmethod + def invite_x_users_and_verify_VF_appers_for_invited(user_content, engName): + inviteEmail = Helper.rand_string('randomString') + "@intl." + ServiceProvider.email + vflist = FEInvite.create_x_vfs(user_content, engName, x=3) + for vfName in vflist: + # Fetch one AT&T user ID. + engagement_id = DBGeneral.select_where( + "engagement_id", "ice_vf", "name", vfName, 1) + engagement_manual_id = DBGeneral.select_where( + "engagement_manual_id", "ice_engagement", "uuid", engagement_id, 1) + engName = engagement_manual_id + ": " + vfName + vf_left_nav_id = "clickable-" + engName + Click.id(vf_left_nav_id) + FEWizard.invite_team_members_modal(inviteEmail) + FEGeneral.refresh() + # validations + FEInvite.validations_for_user2(user_content, inviteEmail, vflist) diff --git a/services/frontend/fe_next_step.py b/services/frontend/fe_next_step.py new file mode 100644 index 0000000..be59949 --- /dev/null +++ b/services/frontend/fe_next_step.py @@ -0,0 +1,56 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +''' +Created on 20 Jul 2017 +''' +from services.constants import Constants +from services.frontend.base_actions.click import Click +from services.frontend.base_actions.wait import Wait + + +class FENextStep(object): + + @staticmethod + def check_select_deselect_all_files(): + Click.id(Constants.Dashboard.Overview.NextSteps.Add.AssociatedFiles.ID) + Click.link_text( + Constants.Dashboard.Overview.NextSteps.Add.AssociatedFiles.SELECT_ALL_FILES_NAME) + Wait.text_by_id( + Constants.Dashboard.Overview.NextSteps.Add.AssociatedFiles.ID, + Constants.Dashboard.Overview.NextSteps.Add.AssociatedFiles.ALL_FILES_SELECTED) diff --git a/services/frontend/fe_overview.py b/services/frontend/fe_overview.py new file mode 100644 index 0000000..8d05f0c --- /dev/null +++ b/services/frontend/fe_overview.py @@ -0,0 +1,427 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +import datetime + +from django.utils import timezone +from selenium.webdriver.support.select import Select + +from services.constants import Constants +from services.database.db_general import DBGeneral +from services.database.db_user import DBUser +from services.database.db_virtual_function import DBVirtualFunction +from services.frontend.base_actions.click import Click +from services.frontend.base_actions.enter import Enter +from services.frontend.base_actions.get import Get +from services.frontend.base_actions.wait import Wait +from services.frontend.fe_general import FEGeneral +from services.frontend.fe_user import FEUser +from services.frontend.fe_wizard import FEWizard +from services.helper import Helper +from services.logging_service import LoggingServiceFactory +from services.session import session + +logger = LoggingServiceFactory.get_logger() + +class FEOverview: + + @staticmethod + def click_on_vf(user_content): + vfFullName = user_content[ + 'engagement_manual_id'] + ": " + user_content['vfName'] + Enter.text_by_id(Constants.Dashboard.LeftPanel.SearchBox.ID, user_content[ + 'vfName']) + Click.id(Constants.Dashboard.LeftPanel.SearchBox.Results.ID % + user_content['vfName']) + Wait.text_by_id( + Constants.Dashboard.Overview.Title.ID, vfFullName) + + @staticmethod + def go_to_eng_overview_by_clicking_on_the_created_NS(user_content): + logger.debug( + "Go to engagement's overview by clicking on the created Next Step") + Click.name(user_content['engagement_manual_id'], wait_for_page=True) + Wait.text_by_id( + Constants.Dashboard.Overview.Title.ID, user_content['engagement_manual_id'] + ":", wait_for_page=True) + FEGeneral.re_open(Constants.Default.LoginURL.TEXT) + logger.debug("Login with EL user " + user_content['el_email']) + FEUser.login(user_content['el_email'], Constants.Default.Password.TEXT) + # Query to select all assigned next steps on TODO state # + el_native_id = str(DBGeneral.select_where( + "id", "ice_user_profile", "email", user_content['el_email'], 1)) + queryStr = "SELECT count(*) FROM ice_user_profile AS users, ice_next_step_assignees AS assignees, ice_next_step AS ns WHERE users.id=" + \ + el_native_id + \ + " AND users.id=assignees.iceuserprofile_id AND assignees.nextstep_id=ns.uuid AND ns.state='Incomplete';" + el_assigned_ns = str(DBGeneral.select_query(queryStr)) + logger.debug("el_assigned_ns=" + el_assigned_ns) + Wait.page_has_loaded() + if (int(el_assigned_ns) >= 5): + logger.debug( + "EL has 5 or more assigned next steps, checking that only 5 are shown") + ns_list = Get.by_id("next-steps-list") + if (ns_list.count("Engagement - ") > 5): + logger.error("More than 5 next steps are listed in dashboard.") + raise + + @staticmethod + def complete_defaults_nextsteps(engagement_id): + # NEXT STEP ID + next_steps = DBVirtualFunction.select_next_steps_uuids_by_stage( + engagement_id, Constants.EngagementStages.INTAKE) + for next_step in next_steps: + Wait.id(next_step) + Click.id(next_step, wait_for_page=True) + + @staticmethod + def check_stage_notifications(stage): + activityLogID = "activity-log-0" + activityLogMsg = "Engagement stage is now %s" % stage + uiActivityLog = Get.by_id(activityLogID) + if activityLogMsg not in uiActivityLog: + return False + return True + + @staticmethod + def check_stage_next_steps(stage, engagement_uuid): + ns_list = DBGeneral.select_where_and("description", "ice_next_step", + "engagement_id", engagement_uuid, + "engagement_stage", stage, 0) # List of next steps from DB. + logger.debug("Got list of Next Steps for current stage " + stage) + for i in range(len(ns_list)): + ns_description = ns_list[i] # Value number i from the list. + ns_uuid = DBGeneral.select_where_and("uuid", "ice_next_step", + "engagement_id", engagement_uuid, + "description", ns_description, 1) + logger.debug( + "Compare presented text of next step with the text from DB.") + portal_ns = Get.by_id("step-" + ns_uuid) + # Get from UI the text of relevant next step. + if ns_description not in portal_ns: + logger.error("Next step wasn't found in stage " + stage) + raise + + @staticmethod + def change_engagement_stage(next_stage, is_negative=False): + # Click on next stage. + Click.id(Constants.Dashboard.Overview.Stage.Set.ID + next_stage) + txtLine2ID = "modal-message-" + next_stage + if is_negative: + session.run_negative( + lambda: Wait.id(txtLine2ID), "Error: modal window opened.") + else: + Wait.text_by_id( + txtLine2ID, "Are you sure you want to set the Engagement's stage to " + next_stage + "?") + # Click on Approve (after validations inside window). + Click.xpath( + Constants.Dashboard.Overview.Stage.Approve.XPATH, wait_for_page=True) + + @staticmethod + def check_progress(expected_progress): + currentProgress = Get.by_id( + Constants.Dashboard.Overview.Progress.Percent.ID) + Helper.internal_assert(currentProgress, expected_progress) + + @staticmethod + def check_vnf_version(expected_progress): + current_vnf_value = Get.by_css( + "." + Constants.Dashboard.Overview.Progress.VnfVersion.CLASS) + Helper.internal_assert(current_vnf_value, expected_progress) + + @staticmethod + def set_progress(new_value): + Click.id(Constants.Dashboard.Overview.Progress.Change.ID) + Helper.internal_assert(Constants.Dashboard.Overview.Progress.Wizard.Title.TEXT, + Get.by_id(Constants.Dashboard.Modal.TITLE_ID)) + Enter.text_by_name( + Constants.Dashboard.Overview.Progress.Wizard.NAME, new_value) + Wait.text_by_css(Constants.SubmitButton.CSS, + Constants.Dashboard.Overview.Progress.Wizard.Button.TEXT) + Click.css(Constants.SubmitButton.CSS) + Wait.modal_to_dissappear() + + @staticmethod + def delete_next_step(next_step_uuid): + Click.id("step-" + next_step_uuid, wait_for_page=True) + Click.id("delete-" + next_step_uuid, wait_for_page=True) + Wait.text_by_id( + Constants.Dashboard.GeneralPrompt.Title.ID, "Delete Step") + Click.id( + Constants.Dashboard.GeneralPrompt.ApproveButton.ID, wait_for_page=True) + Wait.id_to_dissappear("test_" + next_step_uuid) + + @staticmethod + def click_on_admin_dropdown(): + Click.id( + Constants.Dashboard.Overview.AdminDropdown.ID, wait_for_page=True) + + @staticmethod + def click_on_archeive_engagement_from_dropdown(): + FEOverview.click_on_admin_dropdown() + Click.link_text( + Constants.Dashboard.Overview.AdminDropdown.ArchiveEngagement.LINK_TEXT, wait_for_page=True) + + @staticmethod + def archive_engagement_modal(engagement_manual_id, vf_name): + Wait.text_by_id(Constants.Dashboard.Overview.AdminDropdown.ArchiveEngagement.Wizard.Title.ID, + Constants.Dashboard.Overview.AdminDropdown.ArchiveEngagement.Wizard.Title.TEXT) + random_reason = Helper.rand_string() + Enter.text_by_name(Constants.Dashboard.Overview.AdminDropdown.ArchiveEngagement.Wizard.Reason.NAME, + random_reason) + Click.id(Constants.SubmitButton.ID) + Wait.text_by_id(Constants.Toast.ID, "Engagement '%s: %s' archived successfully." % + (engagement_manual_id, vf_name)) + query = "select archived_time,archive_reason from ice_engagement where engagement_manual_id='{engagement_manual_id}'".format( + engagement_manual_id=engagement_manual_id) + archived_time, db_reason = DBGeneral.select_query(query, "list") + Helper.assertTrue(archived_time != None) + Helper.internal_assert(random_reason, db_reason) + + @staticmethod + def click_on_change_reviewer_from_dropdown(): + FEOverview.click_on_admin_dropdown() + Click.link_text( + Constants.Dashboard.Overview.AdminDropdown.ChangeReviewer.LINK_TEXT) + + @staticmethod + def select_engagement_lead_from_list(el_name): + Wait.name( + Constants.Dashboard.Overview.AdminDropdown.ChangeReviewer.Wizard.Select.NAME, wait_for_page=True) + Select(session.ice_driver.find_element_by_name( + Constants.Dashboard.Overview.AdminDropdown.ChangeReviewer.Wizard.Select.NAME)).select_by_visible_text(el_name) + + @staticmethod + def change_engagement_lead_modal(el_name, is_reviewer=True): + Wait.text_by_id(Constants.Dashboard.Overview.AdminDropdown.ChangeReviewer.Wizard.Title.ID, + Constants.Dashboard.Overview.AdminDropdown.ChangeReviewer.Wizard.Title.TEXT) + FEOverview.select_engagement_lead_from_list(el_name) + if is_reviewer: + Wait.text_by_id( + Constants.Toast.ID, Constants.Dashboard.Overview.AdminDropdown.ChangeReviewer.Toast.TEXT) + else: + Wait.text_by_id( + Constants.Toast.ID, Constants.Dashboard.Overview.AdminDropdown.ChangePeerReviewer.Toast.TEXT) + + @staticmethod + def click_on_change_peer_reviewer_from_dropdown(): + FEOverview.click_on_admin_dropdown() + Click.link_text( + Constants.Dashboard.Overview.AdminDropdown.ChangePeerReviewer.LINK_TEXT) + Wait.text_by_id(Constants.Dashboard.Overview.AdminDropdown.ChangePeerReviewer.Wizard.Title.ID, + Constants.Dashboard.Overview.AdminDropdown.ChangePeerReviewer.Wizard.Title.TEXT) + + @staticmethod + def click_on_update_status_from_dropdown(): + FEOverview.click_on_admin_dropdown() + Click.link_text( + Constants.Dashboard.Overview.AdminDropdown.UpdateStatus.LINK_TEXT) + Wait.text_by_id("update-engagement-status-title", "Update Status") + + @staticmethod + def fill_update_status_form_admin_dropdown(): + random_string = Helper.rand_string() + Enter.text_by_name( + Constants.Dashboard.Overview.AdminDropdown.UpdateStatus.PROGRESS, str(50)) + Enter.date_picker(Constants.Dashboard.Overview.AdminDropdown.UpdateStatus.PROGRESS_CSS, + Constants.Dashboard.Overview.AdminDropdown.UpdateStatus.TARGET) + Enter.date_picker(Constants.Dashboard.Overview.AdminDropdown.UpdateStatus.PROGRESS_CSS, + Constants.Dashboard.Overview.AdminDropdown.UpdateStatus.HEAT) + Enter.date_picker(Constants.Dashboard.Overview.AdminDropdown.UpdateStatus.PROGRESS_CSS, + Constants.Dashboard.Overview.AdminDropdown.UpdateStatus.IMAGE_SACN) + Enter.date_picker(Constants.Dashboard.Overview.AdminDropdown.UpdateStatus.PROGRESS_CSS, + Constants.Dashboard.Overview.AdminDropdown.UpdateStatus.AIC) + Enter.date_picker(Constants.Dashboard.Overview.AdminDropdown.UpdateStatus.PROGRESS_CSS, + Constants.Dashboard.Overview.AdminDropdown.UpdateStatus.ASDC) + Enter.text_by_name( + Constants.Dashboard.Overview.AdminDropdown.UpdateStatus.STATUS, random_string) + Click.css( + Constants.Dashboard.Overview.AdminDropdown.UpdateStatus.SUBMIT, wait_for_page=True) + Wait.text_by_id( + Constants.Toast.ID, Constants.Dashboard.Overview.AdminDropdown.UpdateStatus.SUCCESS_MSG, wait_for_page=True) + Wait.text_by_id( + Constants.Dashboard.Overview.Status.Description.ID, random_string) + + @staticmethod + def get_next_step_description(idx): + return str(Get.by_id("step-description-%s" % idx, wait_for_page=True)) + + @staticmethod + def get_list_of_next_steps(): + i = 0 + ns_list = [] + steps_length = len( + session.ice_driver.find_elements_by_css_selector(".step-indication > li")) + while i < steps_length: + ns_list.append(FEOverview.get_next_step_description(i)) + i += 1 + return ns_list + + @staticmethod + def validate_next_steps_order(steps_uuids): + ui_steps = FEOverview.get_list_of_next_steps() + for idx, step_uuid in enumerate(steps_uuids): + db_step_text = DBVirtualFunction.select_next_step_description( + step_uuid) + Wait.text_by_id(Constants.Dashboard.Overview.NextSteps.Add.Description.STEP_DESC_ID + + str(idx), ui_steps[idx], wait_for_page=True) + if db_step_text != ui_steps[idx]: + raise AssertionError("Next step is not located in expected index. db_step_text = " + + db_step_text + " ui_steps[idx] = " + ui_steps[idx] + "|| uuid = " + step_uuid) + + @staticmethod + def next_steps_filter_by_files(): + Click.id( + Constants.Dashboard.Overview.NextSteps.FilterByFileDropDown.ID) + Click.link_text( + Constants.Dashboard.Overview.NextSteps.FilterByFileDropDown.ANY_FILE_LINK_TEXT) + Click.link_text( + Constants.Dashboard.Overview.NextSteps.FilterByFileDropDown.FILE0_LINK_TEXT) + Click.id( + Constants.Dashboard.Overview.NextSteps.FilterByFileDropDown.ID) + + @staticmethod + def complete_next_step(step_uuid): + Click.id(step_uuid) + + @staticmethod + def complete_next_step_and_wait_for_it_to_disappear(step_uuid): + Click.id(step_uuid) + Wait.id_to_dissappear(step_uuid) + + @staticmethod + def next_steps_filter_by_states(): + Click.id(Constants.Dashboard.Overview.NextSteps.StateDropDown.ID) + Click.link_text( + Constants.Dashboard.Overview.NextSteps.StateDropDown.INCOMPLETE_LINK_TEXT) + Click.link_text( + Constants.Dashboard.Overview.NextSteps.StateDropDown.COMPLETED_LINK_TEXT) + Click.id(Constants.Dashboard.Overview.NextSteps.StateDropDown.ID) + + @staticmethod + def add_next_step(): + Click.id(Constants.Dashboard.Overview.NextSteps.Add.ID) + Wait.text_by_css(Constants.Dashboard.Overview.NextSteps.Add.Title.CSS, + Constants.Dashboard.Overview.NextSteps.Add.Title.TEXT) + ns_description = "New next step - " + \ + Helper.rand_string("randomString") + Click.id(Constants.Dashboard.Overview.NextSteps.Add.Description.ID) + Enter.text_by_id( + Constants.Dashboard.Overview.NextSteps.Add.Description.ID, ns_description) + FEWizard.date_picker_add_ns(0) + Wait.text_by_css(Constants.SubmitButton.CSS, + Constants.Dashboard.Overview.NextSteps.Add.Button.TEXT) + Click.css(Constants.SubmitButton.CSS) + Wait.modal_to_dissappear() + + @staticmethod + def click_on_team_member(full_name): + Click.id(Constants.Dashboard.Overview.TeamMember.MEMBER_ID % full_name) + Wait.id(Constants.Dashboard.Overview.TeamMember.Title.ID) + + @staticmethod + def remove_user_from_eng_team(full_name, is_negative=False): + FEOverview.click_on_team_member(full_name) + if is_negative: + Wait.id_to_dissappear( + Constants.Dashboard.Overview.TeamMember.RemoveUser.ID) + else: + Click.id(Constants.Dashboard.Overview.TeamMember.RemoveUser.ID) + Wait.text_by_id(Constants.Dashboard.GeneralPrompt.UpperTitle.ID, + Constants.Dashboard.Overview.TeamMember.RemoveUser.Title.TEXT % full_name) + Wait.text_by_id(Constants.Dashboard.GeneralPrompt.Title.ID, + Constants.Dashboard.Overview.TeamMember.RemoveUser.Message.TEXT) + Click.id(Constants.Dashboard.GeneralPrompt.ApproveButton.ID) + FEGeneral.refresh() + Wait.id_to_dissappear( + Constants.Dashboard.Overview.TeamMember.MEMBER_ID % full_name) + + @staticmethod + def invite_and_reopen_link(user_content, other_el_email): + enguuid = DBGeneral.select_where( + "uuid", "ice_engagement", "engagement_manual_id", user_content['engagement_manual_id'], 1) + invitation_token = DBUser.select_invitation_token( + "invitation_token", "ice_invitation", "engagement_uuid", enguuid, other_el_email, 1) + inviterURL = Constants.Default.InviteURL.Login.TEXT + invitation_token + FEGeneral.re_open(inviterURL) + + @staticmethod + def create_and_verify_VF_with_VFversion(): + Click.id( + Constants.Dashboard.LeftPanel.AddEngagement.ID, wait_for_page=True) + vfName = FEWizard.add_vf() + version_name = DBVirtualFunction.select_vf_version_by_vf_name(vfName) + vfNameDb = DBVirtualFunction.select_vf_name_by_vf_version(version_name) + Helper.internal_assert(vfNameDb, vfName) + + @staticmethod + def validate_empty_associated_files(): + FEOverview.add_next_step() + Click.id(Constants.Dashboard.Overview.NextSteps.AssociatedFiles.ID) + Wait.text_by_id(Constants.Dashboard.Overview.NextSteps.AssociatedFiles.EmptyMsgID, + Constants.Dashboard.Overview.NextSteps.AssociatedFiles.EmptyMsg) + + @staticmethod + def validate_associated_files(file_name): + Click.id(Constants.Dashboard.Overview.NextSteps.AssociatedFiles.ID) + Wait.text_by_id( + Constants.Dashboard.Overview.NextSteps.AssociatedFiles.FileId, file_name) + + @staticmethod + def validate_bucket_url(eng_manual_id, vf_name): + expected_text = Constants.Dashboard.Overview.BucketURL.TEXT + \ + eng_manual_id + "_" + vf_name.lower() + Wait.text_by_id( + Constants.Dashboard.Overview.BucketURL.ID, expected_text, True) + + @staticmethod + def verify_validation_dates(): + validation_date = Get.by_id( + Constants.Dashboard.Overview.Progress.ValidationsDates.AIC_ID, True) + validation_date = datetime.datetime.strptime( + validation_date, "%m/%d/%y").date() + current_date = timezone.now().date() + Helper.internal_assert(validation_date, current_date) + + @staticmethod + def open_add_next_step_modal_from_overview(): + Click.id(Constants.Dashboard.Overview.NextSteps.Add.ID, + wait_for_page=True) + Wait.text_by_css(Constants.Dashboard.Checklist.AddNS.CSS, + Constants.Dashboard.Overview.NextSteps.Add.TITLE) + Helper.internal_assert( + Constants.Dashboard.Checklist.AddNS.TITLE, + Get.by_css(Constants.FEGeneral.CSS.H2)) diff --git a/services/frontend/fe_user.py b/services/frontend/fe_user.py new file mode 100644 index 0000000..91cf7eb --- /dev/null +++ b/services/frontend/fe_user.py @@ -0,0 +1,403 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +from selenium.webdriver.support.select import Select + +from services.api.api_user import APIUser +from services.api.api_virtual_function import APIVirtualFunction +from services.constants import Constants +from services.database.db_general import DBGeneral +from services.database.db_user import DBUser +from services.frontend.base_actions.click import Click +from services.frontend.base_actions.enter import Enter +from services.frontend.base_actions.get import Get +from services.frontend.base_actions.wait import Wait +from services.frontend.fe_general import FEGeneral +from services.helper import Helper +from services.logging_service import LoggingServiceFactory +from services.session import session + + +logger = LoggingServiceFactory.get_logger() + +class FEUser: + + @staticmethod + def login(email, password, expected_element=Constants.Dashboard.Statuses.Title.ID, element_type="id"): + try: + logger.debug("Verifying and Insert Login page elements:") + logger.debug("Insert Email " + email) + Wait.name(Constants.Login.Email.NAME, wait_for_page=True) + Enter.text_by_name(Constants.Login.Email.NAME, email) + logger.debug("Insert Password") + Enter.text_by_name(Constants.Login.Password.NAME, password) + logger.debug("Click Login Button") + Click.css(Constants.SubmitButton.CSS) + logger.debug("Login Button clicked") + if element_type == 'id': + Wait.id(expected_element, True) + elif element_type == 'css': + Wait.css(expected_element, True) + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "Login FAILED: email=%s password=%s" % (email, password) + logger.error(errorMsg) + raise Exception(errorMsg, e) + + @staticmethod + def relogin(email, password, expected_element=Constants.Dashboard.Statuses.Title.ID, element_type="id"): + FEGeneral.re_open(Constants.Default.LoginURL.TEXT) + FEUser.login(email, password, expected_element, element_type) + + @staticmethod + def logout(): + Click.id(Constants.Dashboard.Avatar.ID) + Click.link_text(Constants.Dashboard.Avatar.Logout.LINK_TEXT) + + @staticmethod + def activate_and_login(email, password, expected_element=Constants.Dashboard.Statuses.Title.ID, element_type="id"): + activationUrl = DBUser.get_activation_url(email) + FEGeneral.re_open(activationUrl) + FEUser.login(email, password, expected_element, element_type) + + @staticmethod + def open_account_form(): + Click.id(Constants.Dashboard.Avatar.ID, wait_for_page=True) + Click.link_text( + Constants.Dashboard.Avatar.Account.LINK_TEXT, wait_for_page=True) + + @staticmethod + # Update account API - only adds new SSH key! + def update_account_and_return_changes(): + try: + Select(session.ice_driver.find_element_by_name( + "company")).select_by_visible_text("Nokia") + randomName = Helper.rand_string("randomString") + Enter.text_by_name("fullname", randomName) + phone = "97258" + Helper.rand_string("randomNumber", 6) + Enter.text_by_name("phone", phone) + password = Constants.Default.Password.NewPass.TEXT + Enter.text_by_name("password", password) + Enter.text_by_name("confirm_password", password) + Wait.text_by_css("button.btn.btn-primary", "Update") + Click.css("button.btn.btn-primary") + Wait.text_by_id( + Constants.Toast.ID, "Account was updated successfully!") + Click.id(Constants.Dashboard.Statuses.ID) + + accountObj = [randomName, phone, password] + return accountObj + # If failed - count the failure and add the error to list of errors. + except: + errorMsg = "Failed in update accaunt ." + raise Exception(errorMsg) + raise + + @staticmethod + def go_to_account(): + try: + FEUser.click_on_avatar() + FEUser.click_on_account() + except Exception as e: + errorMsg = "Failed to go to Account page." + raise Exception(errorMsg, e) + + @staticmethod + def go_to_notifications(): + try: + FEUser.click_on_avatar() + FEUser.click_on_notifications() + Wait.page_has_loaded() + except Exception as e: + errorMsg = "Failed to go to Notifications page." + raise Exception(errorMsg, e) + + @staticmethod + def click_on_avatar(): + try: + Click.id(Constants.Dashboard.Avatar.ID, wait_for_page=True) + except Exception as e: + errorMsg = "Failed to click_on on Avatar." + raise Exception(errorMsg, e) + + @staticmethod + def click_on_admin(): + try: + Click.id( + Constants.Dashboard.Avatar.Admin.Title.ID, wait_for_page=True) + except Exception as e: + errorMsg = "Failed to click_on on Admin." + raise Exception(errorMsg, e) + + @staticmethod + def click_on_feedback(): + Click.id(Constants.Dashboard.Feedback.ID, wait_for_page=True) + Wait.id( + Constants.Dashboard.Feedback.FeedbackModal.SAVE_BTN_ID, wait_for_page=True) + + @staticmethod + def validate_feedback(description, user_email): + query = "SELECT user_id FROM ice_feedback where description = '{desc}'".format( + desc=description) + feedback_user_uuid = DBGeneral.select_query(query) + query = "SELECT id FROM ice_user_profile where email = '{email}'".format( + email=user_email) + user_uuid = DBGeneral.select_query(query) + Helper.internal_assert(user_uuid, feedback_user_uuid) + + @staticmethod + def add_feedback(): + Wait.css("textarea[name=\"description\"]", wait_for_page=True) + description = Helper.rand_string("randomString") + Enter.text_by_css("textarea[name=\"description\"]", description) + Click.id( + Constants.Dashboard.Feedback.FeedbackModal.SAVE_BTN_ID, wait_for_page=True) + Wait.text_by_id(Constants.Toast.ID, + "Feedback was sent successfully.", wait_for_page=True) + return description + + @staticmethod + def click_on_account(): + try: + Click.link_text(Constants.Dashboard.Avatar.Account.LINK_TEXT) + Wait.text_by_css(Constants.Dashboard.Avatar.Account.Title.CSS, + Constants.Dashboard.Avatar.Account.Title.TEXT) + except Exception as e: + errorMsg = "Failed to click_on on Admin." + raise Exception(errorMsg, e) + + @staticmethod + def click_on_notifications(): + try: + Click.link_text( + Constants.Dashboard.Avatar.Notifications.LINK_TEXT, wait_for_page=True) + Wait.text_by_id(Constants.Dashboard.Avatar.Notifications.Title.ID, + Constants.Dashboard.Avatar.Notifications.Title.TEXT, wait_for_page=True) + except Exception as e: + errorMsg = "Failed to click_on on Admin." + raise Exception(errorMsg, e) + + @staticmethod + def go_to_admin(): + try: + FEUser.click_on_avatar() + FEUser.click_on_admin() + except Exception as e: + errorMsg = "Failed to go to Admin page." + raise Exception(errorMsg, e) + + @staticmethod + def assigned_one_NS_to_user(user_content): + nextStepsNumber = int( + Get.by_id("next-steps-header").split('(')[1][:-1]) + if (nextStepsNumber != 0): + logger.error("assigned ns: " + str(nextStepsNumber)) + logger.error( + "APIUser should not have assigned next steps at first login.") + raise + if (Get.by_id("next-steps-list") != "No next steps are assigned to you."): + logger.error( + "No assigned next steps and text 'No next steps are assigned to you.' was not found.") + raise + token = "token " + APIUser.login_user(user_content['el_email']) + user_content['session_token'] = token + logger.debug( + "Adding new next step (via api) and assigning it to user " + user_content['full_name']) + APIVirtualFunction.add_next_step(user_content) + logger.debug( + "Refresh page and look for changes in assigned next steps section:") + FEGeneral.refresh() + logger.debug(" > Check if number has changed in 'Assigned To You'") + Wait.text_by_id( + "next-steps-header", "Assigned To You (1)", wait_for_page=True) + + @staticmethod + def set_ssh_key_from_account(key, is_negative=False): + FEUser.go_to_account() + Enter.text_by_name(Constants.Dashboard.Avatar.Account.SSHKey.NAME, key) + Click.css(Constants.SubmitButton.CSS) + if is_negative: + Wait.text_by_id( + Constants.Toast.ID, Constants.Dashboard.Avatar.Account.SSHKey.UpdateFailed.TEXT) + else: + Wait.text_by_id( + Constants.Toast.ID, Constants.Dashboard.Avatar.Account.Update.Success.TEXT) + + @staticmethod + def reset_password(): + Wait.text_by_css( + Constants.UpdatePassword.Title.CSS, Constants.UpdatePassword.Title.TEXT) + Wait.text_by_css( + Constants.UpdatePassword.SubTitle.CSS, Constants.UpdatePassword.SubTitle.TEXT) + Wait.text_by_css( + Constants.SubmitButton.CSS, Constants.UpdatePassword.Button.TEXT) + Enter.text_by_name( + Constants.UpdatePassword.Password.NAME, Constants.Default.Password.NewPass.TEXT) + Enter.text_by_name( + Constants.UpdatePassword.ConfirmPassword.NAME, Constants.Default.Password.NewPass.TEXT) + Click.css(Constants.SubmitButton.CSS) + Wait.text_by_id( + Constants.Toast.ID, Constants.UpdatePassword.Toast.TEXT) + + @staticmethod + def delete_notification(notificationID): + if isinstance(notificationID, tuple): + notificationID = notificationID[0] + delete_button = Constants.Dashboard.Avatar.Notifications.DeleteNotification.ID + \ + notificationID + # Click on delete button. + Click.id(delete_button, wait_for_page=True) + Wait.id_to_dissappear(delete_button) + + @staticmethod + def validate_notifications(notificationIDs, notification_list): + ui_list = [] + for notifID in notificationIDs: + if isinstance(notifID, tuple): + notifID = notifID[0] + ui_list.append(str(Get.by_id( + Constants.Dashboard.Avatar.Notifications.NotificationColumn.ID + notifID))) + for activity in notification_list: + if not any(activity in s for s in ui_list): + raise AssertionError( + "Activity: \"" + activity + "\" not appears in UI") + + @staticmethod + def click_on_export_excel(user_content): + Enter.text_by_id( + Constants.Dashboard.Statuses.SearchBox.ID, user_content['vfName']) + engName = user_content[ + 'engagement_manual_id'] + ": " + user_content['vfName'] + engSearchID = "eng-" + engName + Wait.id(engSearchID) + # Find the download link and click it + Click.id(Constants.Dashboard.Statuses.ExportExcel.ID) + + @staticmethod + def open_invite_team_member_form(vf_left_nav_id): + Click.id(vf_left_nav_id) + Click.id(Constants.Dashboard.Overview.TeamMember.ID) + Wait.text_by_name(Constants.Dashboard.Wizard.InviteTeamMembers.Title.NAME, + Constants.Dashboard.Wizard.InviteTeamMembers.Title.TEXT) + + @staticmethod + def invite_single_user_to_team(email): + Enter.text_by_name("email", email, wait_for_page=True) + Click.css(Constants.SubmitButton.CSS, wait_for_page=True) + + @staticmethod + def go_to_user_profile_settings(): + FEUser.go_to_account() + Click.id( + Constants.Dashboard.Avatar.Account.UserProfileSettings.ID, wait_for_page=True) + Wait.text_by_id(Constants.Dashboard.Avatar.Account.UserProfileSettings.TitleID, + Constants.Dashboard.Avatar.Account.UserProfileSettings.TitleText, wait_for_page=True) + + @staticmethod + def check_user_profile_settings_checkboxes(): + Click.id( + Constants.Dashboard.Avatar.Account.UserProfileSettings.ReceiveEmailsID, wait_for_page=True) + Click.id( + Constants.Dashboard.Avatar.Account.UserProfileSettings.ReceiveEmailEveryTimeID, wait_for_page=True) + Click.id( + Constants.Dashboard.Avatar.Account.UserProfileSettings.ReceiveDigestEmailID, wait_for_page=True) + Click.id( + Constants.Dashboard.Avatar.Account.UserProfileSettings.UpdateButtonID, wait_for_page=True) + + @staticmethod + def validate_user_profile_settings_checkboxes(checked): + Wait.page_has_loaded() + receive_emails = Get.is_selected_by_id( + Constants.Dashboard.Avatar.Account.UserProfileSettings.ReceiveEmailsID, wait_for_page=True) + Helper.internal_assert(receive_emails, checked) + receive_notifications = \ + Get.is_selected_by_id( + Constants.Dashboard.Avatar.Account.UserProfileSettings.ReceiveNotificationsID) + receive_email_every_time = \ + Get.is_selected_by_id( + Constants.Dashboard.Avatar.Account.UserProfileSettings.ReceiveEmailEveryTimeID) + Helper.internal_assert(receive_email_every_time, checked) + receive_digest_email = \ + Get.is_selected_by_id( + Constants.Dashboard.Avatar.Account.UserProfileSettings.ReceiveDigestEmailID, wait_for_page=True) + Helper.internal_assert(receive_digest_email, not checked) + + @staticmethod + def compare_notifications_count_for_user(expected_count): + Wait.text_by_id( + Constants.Dashboard.Avatar.Notifications.Count.ID, expected_count, wait_for_page=True) + + @staticmethod + def check_notification_number_is_not_presented(): + FEGeneral.refresh() + Wait.id_to_dissappear( + Constants.Dashboard.Avatar.Notifications.Count.ID, wait_for_page=True) + + @staticmethod + def validate_account_details(full_name, phone_number, ssh_key): + Helper.internal_assert(full_name, Get.value_by_name( + Constants.Dashboard.Avatar.Account.FullName.NAME)) + Helper.internal_assert(phone_number, Get.value_by_name( + Constants.Dashboard.Avatar.Account.Phone.NAME)) + Helper.internal_assert( + ssh_key, Get.value_by_name(Constants.Dashboard.Avatar.Account.SSHKey.NAME)) + + @staticmethod + def check_rgwa_access_key(my_key): + Wait.text_by_id( + Constants.Dashboard.Avatar.Account.RGWA.Key.KEY_ID, my_key) + + @staticmethod + def check_rgwa_access_secret(my_secret): + Click.id(Constants.Dashboard.Avatar.Account.RGWA.Secret.BUTTON_ID) + Wait.text_by_id( + Constants.Dashboard.Avatar.Account.RGWA.Secret.SECRET_ID, my_secret) + + @staticmethod + def get_rgwa_access_secret(): + Click.id(Constants.Dashboard.Avatar.Account.RGWA.Secret.BUTTON_ID, + wait_for_page=True) + secret = Get.by_id( + Constants.Dashboard.Avatar.Account.RGWA.Secret.SECRET_ID, wait_for_page=True) + return secret + + @staticmethod + def check_rgwa_access_secret_not_presented(): + Wait.text_by_id( + Constants.Dashboard.Avatar.Account.RGWA.Secret.SECRET_ID, + Constants.Dashboard.Avatar.Account.RGWA.Secret.SECRET_TEXT) diff --git a/services/frontend/fe_wizard.py b/services/frontend/fe_wizard.py new file mode 100644 index 0000000..777fe52 --- /dev/null +++ b/services/frontend/fe_wizard.py @@ -0,0 +1,216 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +from datetime import datetime + +from selenium.webdriver.support.ui import Select + +from services.constants import Constants, ServiceProvider +from services.frontend.base_actions.click import Click +from services.frontend.base_actions.enter import Enter +from services.frontend.base_actions.wait import Wait +from services.helper import Helper +from services.logging_service import LoggingServiceFactory +from services.session import session + + +logger = LoggingServiceFactory.get_logger() + +class FEWizard: + + E2Edate = None + + @staticmethod + def add_vf(): + try: + logger.debug("Tab Add Virtual Functions") + Wait.text_by_css( + Constants.Dashboard.Wizard.Title.CSS, Constants.Dashboard.Wizard.AddVF.Title.TEXT, wait_for_page=True) + vfName = "newVF" + Helper.rand_string("randomString") + vfVersion = "newVFVersion" + \ + Helper.rand_string( + "randomNumber") + Helper.rand_string("randomString") + Enter.text_by_name("virtualFunction", vfName) + Enter.text_by_name("VFversion", vfVersion, wait_for_page=True) + FEWizard.date_picker_wizard() + Select(session.ice_driver.find_element_by_id( + Constants.Dashboard.Wizard.AddVF.AIC_Version.TEXT)).select_by_visible_text("AIC 3.5") + Select(session.ice_driver.find_element_by_id( + Constants.Dashboard.Wizard.AddVF.ECOMP_Release.TEXT)).select_by_visible_text("Unknown") + session.E2Edate = FEWizard.get_lab_entry_date() + Click.css(Constants.SubmitButton.CSS, wait_for_page=True) + Wait.page_has_loaded() + Wait.name_to_dissappear("Add Virtual Function") + return vfName + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "Failed to add a Virtual Function via modal window. Exception " + \ + str(e) + raise Exception(errorMsg) + + @staticmethod + def get_lab_entry_date(): + E2Edate = session.ice_driver.find_element_by_id( + "add-vf-hidden-target-lab-date").get_attribute("value") + return str(E2Edate) + + @staticmethod + def add_vendor_contact(): + logger.debug("Tab Add Vendor Contact") + Wait.text_by_css(Constants.Dashboard.Wizard.Title.CSS, + Constants.Dashboard.Wizard.AddVendorContact.Title.TEXT, wait_for_page=True) + Select(session.ice_driver.find_element_by_name( + "company")).select_by_visible_text("Ericsson") + fullname = Helper.rand_string( + "randomString") + Helper.rand_string("randomString") + Enter.text_by_name("fullname", fullname) + email = Helper.rand_string("randomString") + "@ericson.com" + Enter.text_by_name("email", email) + phone = "201" + Helper.rand_string("randomNumber", 6) + Enter.text_by_name("phone", phone) + Click.css(Constants.SubmitButton.CSS, wait_for_page=True) + Wait.name_to_dissappear("Add Vendor Contact", wait_for_page=True) + vendor = {"company": "Ericsson", "full_name": fullname, + "email": email, "phone": phone} + return vendor + + @staticmethod + def add_service_provider_internal(): + logger.debug( + "Tab Add " + ServiceProvider.MainServiceProvider + " Sponsor") + Wait.text_by_css( + Constants.Dashboard.Wizard.Title.CSS, "Add " + ServiceProvider.MainServiceProvider + " Sponsor") + fullname = Helper.rand_string( + "randomString") + Helper.rand_string("randomString") + Enter.text_by_name("fullname", fullname) + email = Helper.rand_string( + "randomString") + "@" + ServiceProvider.email + Enter.text_by_name("email", email) + phone = "201" + Helper.rand_string("randomNumber", 6) + logger.debug(phone) + Enter.text_by_name("phone", phone) + Click.css(Constants.SubmitButton.CSS) + Wait.name_to_dissappear("Add AT&T Sponsor") + sponsor = {"company": "AT&T", "full_name": fullname, + "email": email, "phone": phone} + return sponsor + + @staticmethod + def invite_team_members(email): + try: + logger.debug("Tab Invite Team Members") + Wait.text_by_name(Constants.Dashboard.Wizard.InviteTeamMembers.Title.NAME, + Constants.Dashboard.Wizard.InviteTeamMembers.Title.TEXT) + Enter.text_by_name("email", email) + Wait.text_by_css( + Constants.SubmitButton.CSS, Constants.Dashboard.Wizard.InviteTeamMembers.Button.TEXT) + Click.css(Constants.SubmitButton.CSS) + Wait.name_to_dissappear( + Constants.Dashboard.Wizard.InviteTeamMembers.Title.NAME) + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "FAILED in Tab Invite Team Members. Exception = %s" % e + raise Exception(errorMsg) + + @staticmethod + def add_ssh_key(is_negative=False): + logger.debug("About to add an SSH Key in modal window") + try: # Add SSH Key from modal window and return key value. + Wait.text_by_name(Constants.Dashboard.Wizard.AddSSHKey.Title.NAME, + Constants.Dashboard.Wizard.AddSSHKey.Title.TEXT) + # Generate an SSH Public Key. + sshKey = Helper.generate_sshpub_key() + if is_negative: + sshKey = sshKey[8:] + Enter.text_by_name("key", sshKey) + + # Check that the submit button exists. + Wait.text_by_css( + Constants.SubmitButton.CSS, Constants.Dashboard.Wizard.AddSSHKey.Title.TEXT) + + Click.css(Constants.SubmitButton.CSS) # Click on submit button. + if is_negative: + Wait.text_by_id( + Constants.Toast.ID, Constants.Dashboard.Avatar.Account.SSHKey.UpdateFailed.TEXT) + else: + Wait.name_to_dissappear( + Constants.Dashboard.Wizard.AddSSHKey.Title.NAME) + logger.debug("SSH Key added via modal window.") + return sshKey + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "Failed to add an SSH Key in the modal window. Exception=" + \ + str(e) + raise Exception(errorMsg) + + @staticmethod + def invite_team_members_modal(email): + try: + Click.id( + Constants.Dashboard.Overview.TeamMember.ID, wait_for_page=True) + Wait.text_by_css(Constants.Dashboard.Wizard.Title.CSS, + Constants.Dashboard.Wizard.InviteTeamMembers.Title.TEXT) + Enter.text_by_name("email", email) + Wait.text_by_css( + Constants.SubmitButton.CSS, Constants.Dashboard.Wizard.InviteTeamMembers.Button.TEXT) + Wait.css_to_dissappear( + '.inviteMembers-form button[disabled="disabled"].btn.btn-primary') + Wait.css(".inviteMembers-form button.btn.btn-primary") + Click.css(".inviteMembers-form button.btn.btn-primary") + Wait.modal_to_dissappear() + # If failed - count the failure and add the error to list of errors. + except Exception as e: + errorMsg = "FAILED in PopUp Invite Team Members. Exception=" + \ + str(e) + raise Exception(errorMsg) + + @staticmethod + def date_picker_add_ns(count): + try: + session.ice_driver.execute_script("var el = angular.element(document.querySelector('.addNextSteps')); el.scope().vm.nextSteps[" + str( + count) + "].duedate = new Date('" + str(datetime.today().isoformat()) + "')") + Click.css("div.modal-content", wait_for_page=True) + except Exception as e: + errorMsg = "Failed to select date with datePicker." + + raise Exception(errorMsg, str(e)) + + @staticmethod + def date_picker_wizard(): + Enter.date_picker('#e2e-lab-entry-date', 'choice.TargetLab') + Click.css('input[name="virtualFunction"]', wait_for_page=True) diff --git a/services/helper.py b/services/helper.py new file mode 100644 index 0000000..58769fe --- /dev/null +++ b/services/helper.py @@ -0,0 +1,210 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +import os +import random +import string +import subprocess +import unittest + +from cryptography.hazmat.backends import default_backend as crypto_default_backend, \ + default_backend +from cryptography.hazmat.primitives import serialization as crypto_serialization +from cryptography.hazmat.primitives.asymmetric import rsa +from django.conf import settings + +from services.constants import Constants +from services.database.db_user import DBUser +from services.logging_service import LoggingServiceFactory +from utils.authentication import JWTAuthentication + + +logger = LoggingServiceFactory.get_logger()
+
+class Helper:
+
+ tc = unittest.TestCase('__init__')
+
+ @staticmethod
+ def rand_string(type_of_value='randomString', numberOfDigits=0):
+ letters_and_numbers = string.ascii_letters + string.digits
+ if type_of_value == 'email':
+ myEmail = ''.join(random.choice(letters_and_numbers) for _ in range(
+ 4)) + "@" + ''.join(random.choice(string.ascii_uppercase) for _ in range(4)) + ".com"
+ return "ST" + myEmail
+ elif type_of_value == 'randomNumber':
+ randomNumber = ''.join("%s" % random.randint(2, 9)
+ for _ in range(0, (numberOfDigits + 1)))
+ return randomNumber
+ elif type_of_value == 'randomString':
+ randomString = "".join(random.sample(letters_and_numbers, 5))
+ return "ST" + randomString
+ else:
+ raise Exception("invalid rand type")
+
+ @staticmethod
+ def rand_invite_email():
+ inviteEmail = "automationqatt" + \
+ Helper.rand_string("randomString") + "@gmail.com"
+ return inviteEmail
+
+ @staticmethod
+ def generate_sshpub_key():
+ try:
+ logger.debug("About to generate SSH Public Key")
+ key = rsa.generate_private_key(
+ public_exponent=65537,
+ key_size=2048,
+ backend=default_backend()
+ )
+ private_key = key.private_bytes(
+ encoding=crypto_serialization.Encoding.PEM,
+ format=crypto_serialization.PrivateFormat.TraditionalOpenSSL,
+ encryption_algorithm=crypto_serialization.NoEncryption())
+ public_key = key.public_key().public_bytes(
+ crypto_serialization.Encoding.OpenSSH,
+ crypto_serialization.PublicFormat.OpenSSH
+ ).decode("utf-8")
+
+ logger.debug("Generated SSH Public Key: " + public_key)
+ except Exception as e: # If failed write to log the error and return 'None'.
+ logger.error(e)
+ logger.error("Failed to generate SSH Public Key.")
+ raise e
+ return public_key
+
+ @staticmethod
+ def check_admin_ssh_existence(path, admin_ssh):
+ if admin_ssh == open(path).read().rstrip('\n'):
+ logger.debug(
+ "Admin SSH already defined in DB and equal to the one stored on the local system.")
+ return True
+ return False
+
+ @staticmethod
+ def get_or_create_rsa_key_for_admin():
+ try: # Create pair of keys for the given user and return his public key.
+ ssh_folder = Constants.Paths.SSH.PATH
+ public_file = ssh_folder + "id_rsa.pub"
+ privateFile = ssh_folder + "id_rsa"
+ admin_ssh_exist_and_equal = False
+ admin_ssh = None
+ if not os.path.exists(ssh_folder):
+ os.makedirs(ssh_folder)
+ elif os.path.exists(public_file):
+ admin_ssh = DBUser.retrieve_admin_ssh_from_db()
+ admin_ssh_exist_and_equal = Helper.check_admin_ssh_existence(
+ public_file, admin_ssh)
+ # TODO find pending gitlab bug causing old ssh key not be updated in gitlab cache
+ if False and admin_ssh_exist_and_equal:
+ return admin_ssh
+ else:
+ logger.debug("Private key file: " + privateFile +
+ "\nPublice key file: " + public_file)
+ key = rsa.generate_private_key(
+ backend=crypto_default_backend(),
+ public_exponent=65537,
+ key_size=2048
+ )
+ private_key = key.private_bytes(
+ crypto_serialization.Encoding.PEM,
+ crypto_serialization.PrivateFormat.PKCS8,
+ crypto_serialization.NoEncryption()).decode("utf-8")
+ public_key = key.public_key().public_bytes(
+ crypto_serialization.Encoding.OpenSSH,
+ crypto_serialization.PublicFormat.OpenSSH
+ ).decode("utf-8")
+
+ with open(privateFile, 'w') as content_file:
+ os.chmod(privateFile, 0o600)
+ content_file.write(private_key) # Save private key to file.
+ logger.debug(
+ "Private key created successfully for admin")
+ user_pub_key = public_key
+ with open(public_file, 'w') as content_file:
+ content_file.write(public_key) # Save public key to file.
+ logger.debug("Public key created successfully for admin")
+ cmd = 'ssh-keyscan ' + \
+ settings.GITLAB_URL[7:-1] + ' >> ' + \
+ ssh_folder + 'known_hosts'
+ # Create known_hosts file and add GitLab to it.
+ subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE)
+ logger.debug("Added GitLab to known_hosts")
+ return user_pub_key
+ except Exception as error:
+ logger.error(
+ "_-_-_-_-_- Unexpected error in get_or_create_rsa_key_for_admin: %s" % error)
+ raise Exception("Failed to create SSH keys for user admin", error)
+
+ @staticmethod
+ def internal_assert(x, y):
+ try:
+ Helper.tc.assertEqual(str(x), str(y))
+ except Exception as e:
+ raise Exception("AssertionError: \"" + str(x) +
+ "\" != \"" + str(y) + "\"", e)
+
+ @staticmethod
+ def internal_assert_boolean(x, y):
+ try:
+ Helper.tc.assertEqual(str(x), str(y))
+ return True
+ except Exception as e:
+ raise Exception("AssertionError: \"" + str(x) +
+ "\" != \"" + str(y) + "\"", e)
+
+ @staticmethod
+ def internal_not_equal(x, y):
+ try:
+ Helper.tc.assertNotEqual(x, y)
+ except Exception as e:
+ raise Exception("AssertionError: \"" + str(x) +
+ "\" != \"" + str(y) + "\"", e)
+
+ @staticmethod
+ def get_reset_passw_url(email):
+ jwtObj = JWTAuthentication()
+ token = jwtObj.createPersonalTokenWithExpiration(email)
+ resetPasswURL = Constants.Default.LoginURL.TEXT + "?t=" + token
+ return resetPasswURL
+
+ @staticmethod
+ def assertTrue(expr, msg=None):
+ """Check that the expression is true."""
+ if expr != True:
+ raise Exception("AssertionError: \"not expr")
diff --git a/services/logging_service.py b/services/logging_service.py new file mode 100644 index 0000000..3ae7b75 --- /dev/null +++ b/services/logging_service.py @@ -0,0 +1,20 @@ +import logging + + +class LoggingServiceFactory(object): + __logger = None + + def __init__(self): + if self.__logger is None: + self.__set_logger() + + @classmethod + def __set_logger(cls): + if cls.__logger is None: + cls.__logger = logging.getLogger('vvp-ci.logger') + + @classmethod + def get_logger(cls): + if cls.__logger is None: + cls.__set_logger() + return cls.__logger diff --git a/services/session.py b/services/session.py new file mode 100644 index 0000000..174f54b --- /dev/null +++ b/services/session.py @@ -0,0 +1,106 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +from selenium import webdriver + + +class SessionSingletone(): + positive_wait_until_retires = 60 + positive_wait_until_time_pause = 0.5 + positive_wait_until_time_pause_long = 1.5 + positive_wait_until_implicit_time = 10 + positive_timeout = 10 + + negative_wait_until_retires = 5 + negative_wait_until_time_pause = 0.5 + negative_wait_until_implicit_time = 0.5 + negative_timeout = 5 + + errorCounter = 0 + errorList = "" + createTemplatecount = False + + def __init__(self): + self.wait_until_retires = self.positive_wait_until_retires + self.wait_until_time_pause = self.positive_wait_until_time_pause + self.wait_until_time_pause_long = self.positive_wait_until_time_pause_long + self.wait_until_implicit_time = self.positive_wait_until_implicit_time + self.test = '123' + self.ice_driver = None + + def setup_driver(self): + self.ice_driver = webdriver.Firefox() + return self.ice_driver + + def get_driver(self): + return self.ice_driver + + def close_driver(self): + self.ice_driver.quit() + self.ice_driver = None + + def start_negative(self): + """Changing parameters to reduce negative tests run-time""" + self.wait_until_retires = self.negative_wait_until_retires + self.wait_until_time_pause = self.negative_wait_until_time_pause + self.wait_until_implicit_time = self.negative_wait_until_implicit_time + self.timeout = self.negative_timeout + session.ice_driver.implicitly_wait(self.wait_until_implicit_time) + + def end_negative(self): + """Change back the parameters to suite positive tests""" + self.wait_until_retires = self.positive_wait_until_retires + self.wait_until_time_pause = self.positive_wait_until_time_pause + self.wait_until_implicit_time = self.positive_wait_until_implicit_time + self.timeout = self.positive_timeout + session.ice_driver.implicitly_wait(self.wait_until_implicit_time) + + def run_negative(self, run_me, error_msg): + self.start_negative() + try: + run_me() # click.css + except: + # will run if click does NOT succeed + self.errorCounter = 0 + self.errorList = "" + else: + # will run if click SUCCEED + raise Exception(error_msg) + self.end_negative() + +session = SessionSingletone() diff --git a/services/types.py b/services/types.py new file mode 100644 index 0000000..7dbbe94 --- /dev/null +++ b/services/types.py @@ -0,0 +1,91 @@ + +# ============LICENSE_START========================================== +# org.onap.vvp/test-engine +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +from services.api.api_bridge import APIBridge +from services.api.api_checklist import APIChecklist +from services.api.api_gitlab import APIGitLab +from services.api.api_jenkins import APIJenkins +from services.api.api_user import APIUser +from services.api.api_virtual_function import APIVirtualFunction +from services.database.db_checklist import DBChecklist +from services.database.db_cms import DBCMS +from services.database.db_general import DBGeneral +from services.database.db_user import DBUser +from services.database.db_virtual_function import DBVirtualFunction +from services.frontend.fe_checklist import FEChecklist +from services.frontend.fe_cms import FECms +from services.frontend.fe_dashboard import FEDashboard +from services.frontend.fe_detailed_view import FEDetailedView +from services.frontend.fe_general import FEGeneral +from services.frontend.fe_invite import FEInvite +from services.frontend.fe_overview import FEOverview +from services.frontend.fe_user import FEUser +from services.frontend.fe_wizard import FEWizard +from services.frontend.fe_checklist_template import FEChecklistTemplate +from services.api.api_rados import APIRados + + +class Frontend: + User = FEUser() + Invite = FEInvite() + Checklist = FEChecklist() + Dashboard = FEDashboard() + DetailedView = FEDetailedView() + General = FEGeneral() + Overview = FEOverview() + Wizard = FEWizard() + Cms = FECms() + ChecklistTemplate = FEChecklistTemplate() + + +class API: + Bridge = APIBridge() + Checklist = APIChecklist() + GitLab = APIGitLab() + Jenkins = APIJenkins() + Rados = APIRados + User = APIUser() + VirtualFunction = APIVirtualFunction() + + +class DB: + Checklist = DBChecklist() + Cms = DBCMS() + General = DBGeneral() + User = DBUser() + VirtualFunction = DBVirtualFunction() |