mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-22 10:15:35 +01:00
Merge pull request #13849 from danfengliu/add-gui-test-for-system-robot-account
Ad nightly GUI test for system robot account
This commit is contained in:
commit
511bd86930
@ -86,6 +86,8 @@ class DockerAPI(object):
|
||||
self.DCLIENT2 = docker.from_env()
|
||||
|
||||
def docker_login(self, registry, username, password, expected_error_message = None):
|
||||
ret = ""
|
||||
err_message = ""
|
||||
if username == "" or password == "":
|
||||
print("[Warnig]: No docker credential was provided.")
|
||||
return
|
||||
@ -93,46 +95,55 @@ class DockerAPI(object):
|
||||
expected_error_message = None
|
||||
if registry == "docker":
|
||||
registry = None
|
||||
ret = ""
|
||||
try:
|
||||
print("Docker login: {}:{}:{}".format(registry,username,password))
|
||||
ret = self.DCLIENT.login(registry = registry, username=username, password=password)
|
||||
print("Docker image login commond return:", ret)
|
||||
return ret
|
||||
except docker.errors.APIError as err:
|
||||
except Exception as err:
|
||||
print( "Docker image pull catch exception:", str(err))
|
||||
err_message = str(err)
|
||||
if expected_error_message is None:
|
||||
raise Exception(r" Docker pull image {} failed, error is [{}]".format (image, str(err)))
|
||||
else:
|
||||
print("Docker image login did not catch exception and return message is:", ret)
|
||||
err_message = ret
|
||||
finally:
|
||||
if expected_error_message is not None:
|
||||
print( "docker login error:", str(err))
|
||||
if str(err).lower().find(expected_error_message.lower()) < 0:
|
||||
raise Exception(r"Docker login: Return message {} is not as expected {}".format(str(err), expected_error_message))
|
||||
if str(err_message).lower().find(expected_error_message.lower()) < 0:
|
||||
raise Exception(r" Failed to catch error [{}] when login image {}, return message: {}".format (expected_error_message, image, err_message))
|
||||
else:
|
||||
print(r"Docker image login got expected error message:{}".format(expected_error_message))
|
||||
else:
|
||||
raise Exception(r" Docker login failed, error is [{}]".format (str(err)))
|
||||
if str(err_message).lower().find("error".lower()) >= 0:
|
||||
raise Exception(r" It's was not suppose to catch error when login image {}, return message is [{}]".format (image, err_message))
|
||||
|
||||
def docker_image_pull(self, image, tag = None, expected_error_message = None):
|
||||
ret = ""
|
||||
err_message = ""
|
||||
if tag is not None:
|
||||
_tag = tag
|
||||
else:
|
||||
_tag = "latest"
|
||||
if expected_error_message is "":
|
||||
expected_error_message = None
|
||||
ret = ""
|
||||
try:
|
||||
ret = self.DCLIENT.pull(r'{}:{}'.format(image, _tag))
|
||||
print("Docker image pull commond return:", ret)
|
||||
return ret
|
||||
except Exception as err:
|
||||
if expected_error_message is not None:
|
||||
print( "docker image pull error:", str(err))
|
||||
if str(err).lower().find(expected_error_message.lower()) < 0:
|
||||
raise Exception(r"Pull image: Return message {} is not as expected {}".format(str(err), expected_error_message))
|
||||
else:
|
||||
print( "Docker image pull catch exception:", str(err))
|
||||
err_message = str(err)
|
||||
if expected_error_message is None:
|
||||
raise Exception(r" Docker pull image {} failed, error is [{}]".format (image, str(err)))
|
||||
else:
|
||||
print("Docker image pull did not catch exception and return message is:", ret)
|
||||
err_message = ret
|
||||
finally:
|
||||
if expected_error_message is not None:
|
||||
if str(ret).lower().find(expected_error_message.lower()) < 0:
|
||||
raise Exception(r" Failed to catch error [{}] when pull image {}, return message: {}".format (expected_error_message, image, str(ret)))
|
||||
if str(err_message).lower().find(expected_error_message.lower()) < 0:
|
||||
raise Exception(r" Failed to catch error [{}] when pull image {}, return message: {}".format (expected_error_message, image, err_message))
|
||||
else:
|
||||
print(r"Docker image pull got expected error message:{}".format(expected_error_message))
|
||||
else:
|
||||
if str(ret).lower().find("error".lower()) >= 0:
|
||||
raise Exception(r" It's was not suppose to catch error when pull image {}, return message is [{}]".format (image, ret))
|
||||
if str(err_message).lower().find("error".lower()) >= 0:
|
||||
raise Exception(r" It's was not suppose to catch error when pull image {}, return message is [{}]".format (image, err_message))
|
||||
|
||||
def docker_image_tag(self, image, harbor_registry, tag = None):
|
||||
_tag = base._random_name("tag")
|
||||
@ -148,40 +159,37 @@ class DockerAPI(object):
|
||||
|
||||
def docker_image_push(self, harbor_registry, tag, expected_error_message = None):
|
||||
ret = ""
|
||||
err_message = ""
|
||||
if expected_error_message is "":
|
||||
expected_error_message = None
|
||||
try:
|
||||
ret = self.DCLIENT.push(harbor_registry, tag)
|
||||
print("Docker image push commond return:", ret)
|
||||
except Exception as err:
|
||||
print( "docker image push catch Exception:", str(err))
|
||||
if expected_error_message is not None:
|
||||
print( "docker image push error:", str(err))
|
||||
if str(err).lower().find(expected_error_message.lower()) < 0:
|
||||
raise Exception(r"Push image: Return message {} is not as expected {}".format(str(err), expected_error_message))
|
||||
else:
|
||||
raise Exception(r" Docker push image {} failed, error is [{}]".format (harbor_registry, message))
|
||||
print( "Docker image push catch exception:", str(err))
|
||||
err_message = str(err)
|
||||
if expected_error_message is None:
|
||||
raise Exception(r" Docker push image {} failed, error is [{}]".format (image, str(err)))
|
||||
else:
|
||||
print( "docker image push does not catch Exception:", str(expected_error_message))
|
||||
print("Docker image push did not catch exception and return message is:", ret)
|
||||
err_message = ret
|
||||
finally:
|
||||
if expected_error_message is not None:
|
||||
if str(ret).lower().find(expected_error_message.lower()) < 0:
|
||||
raise Exception(r" Failed to catch error [{}] when push image {}, return message: {}".
|
||||
format (expected_error_message, harbor_registry, str(ret)))
|
||||
if str(err_message).lower().find(expected_error_message.lower()) < 0:
|
||||
raise Exception(r" Failed to catch error [{}] when push image {}, return message: {}".format (expected_error_message, harbor_registry, err_message))
|
||||
else:
|
||||
print("docker image push action return expected error message [{}]".format(expected_error_message))
|
||||
|
||||
print(r"Docker image push got expected error message:{}".format(expected_error_message))
|
||||
else:
|
||||
if str(ret).lower().find("errorDetail".lower()) >= 0:
|
||||
raise Exception(r" It's was not suppose to catch error when push image {}, return message is [{}]".
|
||||
format (harbor_registry, ret))
|
||||
if str(err_message).lower().find("error".lower()) >= 0:
|
||||
raise Exception(r" It's was not suppose to catch error when push image {}, return message is [{}]".format (harbor_registry, err_message))
|
||||
|
||||
def docker_image_build(self, harbor_registry, tags=None, size=1, expected_error_message = None):
|
||||
ret = ""
|
||||
err_message = ""
|
||||
try:
|
||||
baseimage='busybox:latest'
|
||||
self.DCLIENT.login(username=DOCKER_USER, password=DOCKER_PWD)
|
||||
if not self.DCLIENT.images(name=baseimage):
|
||||
print( "docker pull is triggered when building {}".format(harbor_registry))
|
||||
print( "Docker pull is triggered when building {}".format(harbor_registry))
|
||||
self.DCLIENT.pull(baseimage)
|
||||
c=self.DCLIENT.create_container(image='busybox:latest',command='dd if=/dev/urandom of=test bs=1M count=%d' % size )
|
||||
self.DCLIENT.start(c)
|
||||
@ -203,23 +211,20 @@ class DockerAPI(object):
|
||||
self.DCLIENT.remove_container(c)
|
||||
#self.DCLIENT.pull(repo)
|
||||
#image = self.DCLIENT2.images.get(repo)
|
||||
return repo
|
||||
except Exception as err:
|
||||
if expected_error_message is not None:
|
||||
print( "docker image build error:", str(err))
|
||||
if str(err).lower().find(expected_error_message.lower()) < 0:
|
||||
raise Exception(r"Push image: Return message {} is not as expected {}".format(str(err), expected_error_message))
|
||||
else:
|
||||
raise Exception(r" Docker build image {} failed, error is [{}]".format (harbor_registry, str(err)))
|
||||
print( "Docker image build catch exception:", str(err))
|
||||
err_message = str(err)
|
||||
if expected_error_message is None:
|
||||
raise Exception(r" Docker push image {} failed, error is [{}]".format (image, str(err)))
|
||||
else:
|
||||
print("docker image build does not catch Exception:", str(expected_error_message))
|
||||
print("Docker build -> docker image push ret:", ret)
|
||||
print("Docker image build did not catch exception and return message is:", ret)
|
||||
err_message = ret
|
||||
finally:
|
||||
if expected_error_message is not None:
|
||||
if str(ret).lower().find(expected_error_message.lower()) < 0:
|
||||
raise Exception(r" Failed to catch error [{}] when build image {}, return message: {}".
|
||||
format (expected_error_message, harbor_registry, str(ret)))
|
||||
if str(err_message).lower().find(expected_error_message.lower()) < 0:
|
||||
raise Exception(r" Failed to catch error [{}] when build image {}, return message: {}".format (expected_error_message, harbor_registry, err_message))
|
||||
else:
|
||||
print("docker image build return expected error message [{}]".format(expected_error_message))
|
||||
print(r"Docker image build got expected error message: {}".format(expected_error_message))
|
||||
else:
|
||||
if str(ret).lower().find("errorDetail".lower()) >= 0:
|
||||
raise Exception(r" It's was not suppose to catch error when push image {}, return message is [{}]".format (harbor_registry, ret))
|
||||
if str(err_message).lower().find("error".lower()) >= 0:
|
||||
raise Exception(r" It's was not suppose to catch error when build image {}, return message is [{}]".format (harbor_registry, err_message))
|
||||
|
@ -13,8 +13,7 @@ def pull_harbor_image(registry, username, password, image, tag, expected_login_e
|
||||
if expected_login_error_message != None:
|
||||
return
|
||||
time.sleep(2)
|
||||
ret = _docker_api.docker_image_pull(r'{}/{}'.format(registry, image), tag = tag, expected_error_message = expected_error_message)
|
||||
print("Docker pull image return message: {}".format(ret))
|
||||
_docker_api.docker_image_pull(r'{}/{}'.format(registry, image), tag = tag, expected_error_message = expected_error_message)
|
||||
|
||||
def push_image_to_project(project_name, registry, username, password, image, tag, expected_login_error_message = None, expected_error_message = None, profix_for_image = None, new_image=None):
|
||||
print("Start to push image {}/{}/{}:{}".format(registry, project_name, image, tag) )
|
||||
|
@ -156,6 +156,11 @@ Switch To Distribution
|
||||
Retry Element Click xpath=//clr-main-container//clr-vertical-nav-group//span[contains(.,'Distributions')]
|
||||
Sleep 1
|
||||
|
||||
Switch To Robot Account
|
||||
Sleep 1
|
||||
Retry Element Click xpath=//clr-main-container//clr-vertical-nav-group//span[contains(.,'Robot Accounts')]
|
||||
Sleep 1
|
||||
|
||||
Modify Token Expiration
|
||||
[Arguments] ${minutes}
|
||||
Input Text xpath=//*[@id='tokenExpiration'] ${minutes}
|
||||
|
@ -35,6 +35,7 @@ ${create_project_CANCEL_button_xpath} xpath=//button[contains(.,'CANCEL')]
|
||||
${create_project_OK_button_xpath} xpath=//button[contains(.,'OK')]
|
||||
${delete_confirm_btn} xpath=//button[contains(.,'DELETE')]
|
||||
${project_statistics_private_repository_icon} xpath=//project/div/div/div[1]/div/statistics-panel/div/div[2]/div[1]/div[2]/div[2]/statistics/div/span[1]
|
||||
${project_statistics_total_projects_icon} xpath=//div[contains(@class, 'statistic-column-block') and contains(., 'TOTAL')]//div[1]/statistics//span[contains(@class, 'statistic-data')]
|
||||
${repo_delete_confirm_btn} xpath=//clr-modal//button[2]
|
||||
${repo_retag_confirm_dlg} css=${modal-dialog}
|
||||
${repo_delete_on_card_view_btn} //clr-modal//button[contains(.,'DELETE')]
|
||||
|
122
tests/resources/Harbor-Pages/Robot_Account.robot
Normal file
122
tests/resources/Harbor-Pages/Robot_Account.robot
Normal file
@ -0,0 +1,122 @@
|
||||
# Copyright Project Harbor Authors
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file 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
|
||||
|
||||
*** Settings ***
|
||||
Documentation This resource provides any keywords related to the Harbor private registry appliance
|
||||
Resource ../../resources/Util.robot
|
||||
|
||||
*** Variables ***
|
||||
|
||||
|
||||
*** Keywords ***
|
||||
Create A Random Permission Item List
|
||||
${permission_item_all_list}= Create List Push Artifact
|
||||
... Pull Artifact
|
||||
... Delete Artifact
|
||||
... Read Helm Chart
|
||||
... Create Helm Chart Version
|
||||
... Delete Helm Chart Version
|
||||
... Create Tag
|
||||
... Delete Tag
|
||||
... Create Artifact label
|
||||
... Create Scan
|
||||
|
||||
|
||||
Set Suite Variable ${permission_item_all_list}
|
||||
|
||||
${len}= Get Length ${permission_item_all_list}
|
||||
${tmp_list}= Create List @{EMPTY}
|
||||
FOR ${i} IN RANGE 0 ${${len}-1}
|
||||
${r}= Evaluate random.randint(0, 1)
|
||||
Run Keyword If '${r}'=='1' Append To List ${tmp_list} ${permission_item_all_list}[${i}]
|
||||
END
|
||||
Run Keyword If ${tmp_list}==@{EMPTY} Append To List ${tmp_list} ${permission_item_all_list}[${0}]
|
||||
[Return] ${tmp_list}
|
||||
|
||||
Create A Random Project Permission List
|
||||
[Arguments] ${project_count}
|
||||
${tmp_list}= Create List @{EMPTY}
|
||||
FOR ${i} IN RANGE ${project_count}
|
||||
${d}= Get Current Date result_format=%m%s
|
||||
${pro_name}= Set Variable project_${i}_${d}
|
||||
${permission_item_list}= Create A Random Permission Item List
|
||||
Log To Console '@{permission_item_list}'
|
||||
Create An New Project And Go Into Project ${pro_name}
|
||||
${tmp_dict} = Create Dictionary project_name=${pro_name} permission_item_list=@{permission_item_list}
|
||||
Append To List ${tmp_list} ${tmp_dict}
|
||||
END
|
||||
Log To Console tmp_list:'@{tmp_list}'
|
||||
[Return] ${tmp_list}
|
||||
|
||||
Filter Project In Project Permisstion List
|
||||
[Arguments] ${name}
|
||||
Retry Double Keywords When Error Retry Element Click ${save_sys_robot_project_filter_chb} Retry Wait Until Page Contains Element ${save_sys_robot_project_filter_input}
|
||||
Retry Text Input ${save_sys_robot_project_filter_input} ${name}
|
||||
Retry Double Keywords When Error Retry Element Click ${save_sys_robot_project_filter_close_btn} Retry Wait Until Page Not Contains Element ${save_sys_robot_project_filter_input}
|
||||
|
||||
Clear Global Permissions By JaveScript
|
||||
Retry Element Click //button[contains(., 'RESET PERMISSIONS')]
|
||||
FOR ${i} IN RANGE 0 10
|
||||
Execute JavaScript document.getElementsByClassName('dropdown-item')[${i}].click();
|
||||
END
|
||||
|
||||
Select Project Permission
|
||||
[Arguments] ${project_name} ${permission_item_list}
|
||||
FOR ${permission} IN @{permission_item_list}
|
||||
Log To Console project: ${project_name}; permission: ${permission}
|
||||
${item}= Set Variable //clr-dg-row[contains(., '${project_name}')]//clr-dropdown/clr-dropdown-menu//span[contains(., '${permission}')]
|
||||
Execute JavaScript document.evaluate("${item}",document.body,null,9,null).singleNodeValue.click();
|
||||
Capture Page Screenshot
|
||||
END
|
||||
|
||||
Create A New System Robot Account
|
||||
[Arguments] ${name}=${null} ${expiration_type}=default ${expiration_value}=${null} ${description}=${null} ${is_cover_all}=${false} ${cover_all_permission_list}=@{EMPTY} ${project_permission_list}=@{EMPTY}
|
||||
${d}= Get Current Date result_format=%m%s
|
||||
${name}= Set Variable If '${name}'=='${null}' robot_name${d} ${name}
|
||||
Switch To Robot Account
|
||||
Retry Double Keywords When Error Retry Element Click ${new_sys_robot_account_btn} Retry Wait Until Page Contains Element ${sys_robot_account_name_input}
|
||||
Retry Text Input ${sys_robot_account_name_input} ${name}
|
||||
Run Keyword If '${expiration_type}' != 'default' Run Keywords Retry Element Click xpath=${sys_robot_account_expiration_type_select} AND
|
||||
... Retry Element Click xpath=${sys_robot_account_expiration_type_select}//option[@value='${expiration_type}']
|
||||
Run Keyword If '${description}' != '${null}' Retry Text Input ${sys_robot_account_description_textarea} ${description}
|
||||
Run Keyword If '${is_cover_all}' == '${true}' Retry Double Keywords When Error Retry Element Click ${sys_robot_account_coverall_chb} Retry Checkbox Should Be Selected ${sys_robot_account_coverall_chb_input}
|
||||
#Clear Global Permissions
|
||||
Clear Global Permissions By JaveScript
|
||||
# Select project
|
||||
FOR ${project} IN @{project_permission_list}
|
||||
Log To Console project: ${project}
|
||||
Should Be True type($project) is not dict
|
||||
${tmp} = Convert To Dictionary ${project}
|
||||
Should Be True type($tmp) is dict
|
||||
${project_name}= Get From Dictionary ${tmp} project_name
|
||||
Log To Console project_name: ${project_name}
|
||||
${permission_item_list}= Get From Dictionary ${tmp} permission_item_list
|
||||
Log To Console permission_item_list: ${permission_item_list}
|
||||
Filter Project In Project Permisstion List ${project_name}
|
||||
Retry Element Click //clr-dg-row[contains(.,'${project_name}')]//clr-checkbox-wrapper/label
|
||||
Retry Element Click //clr-dg-row[contains(., '${project_name}')]//clr-dropdown/button
|
||||
Select Project Permission ${project_name} ${permission_item_list}
|
||||
END
|
||||
# Save it
|
||||
Retry Double Keywords When Error Retry Element Click ${save_sys_robot_account_btn} Retry Wait Until Page Not Contains Element ${save_sys_robot_account_btn}
|
||||
Retry Double Keywords When Error Retry Element Click ${save_sys_robot_project_paste_icon} Retry Wait Until Page Not Contains Element ${save_sys_robot_project_paste_icon}
|
||||
|
||||
[Return] ${name}
|
||||
|
||||
System Robot Account Exist
|
||||
[Arguments] ${name} ${project_count}
|
||||
Retry Double Keywords When Error Retry Element Click ${filter_dist_btn} Wait Until Element Is Visible And Enabled ${filter_dist_input}
|
||||
Retry Text Input ${filter_dist_input} ${name}
|
||||
Retry Wait Until Page Contains Element //clr-dg-row[contains(.,'${name}') and contains(.,'${project_count} PROJECT')]
|
||||
|
32
tests/resources/Harbor-Pages/Robot_Account_Elements.robot
Normal file
32
tests/resources/Harbor-Pages/Robot_Account_Elements.robot
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright Project Harbor Authors
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file 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
|
||||
|
||||
*** Settings ***
|
||||
Documentation This resource provides any keywords related to the Harbor private registry appliance
|
||||
|
||||
*** Variables ***
|
||||
${new_sys_robot_account_btn} //system-robot-accounts//button/span/span[contains(.,'NEW ROBOT ACCOUNT')]
|
||||
${sys_robot_account_name_input} //*[@id='name']
|
||||
${sys_robot_account_expiration_type_select} //*[@id='expiration-type']
|
||||
${sys_robot_account_expiration_input} //*[@id='robotTokenExpiration']
|
||||
${sys_robot_account_description_textarea} //*[@id='description']
|
||||
${sys_robot_account_coverall_chb_input} xpath=//input[@id='coverAll']
|
||||
${sys_robot_account_coverall_chb} //clr-checkbox-wrapper[contains(@class, 'clr-checkbox-wrapper')]/label[contains(@for, 'coverAll')]
|
||||
${sys_robot_account_permission_list_btn} //form/section//clr-dropdown/button
|
||||
${save_sys_robot_account_btn} //*[@id='system-robot-save']
|
||||
${save_sys_robot_project_filter_chb} //clr-dg-string-filter/clr-dg-filter//clr-icon
|
||||
${save_sys_robot_project_filter_input} //input[contains(@name, 'search')]
|
||||
${save_sys_robot_project_filter_close_btn} //button/clr-icon[contains(@title, 'Close')]
|
||||
${save_sys_robot_project_paste_icon} //hbr-copy-input//clr-icon
|
||||
|
@ -69,6 +69,8 @@ Resource Harbor-Pages/Vulnerability_Elements.robot
|
||||
Resource Harbor-Pages/LDAP-Mode.robot
|
||||
Resource Harbor-Pages/OIDC_Auth.robot
|
||||
Resource Harbor-Pages/OIDC_Auth_Elements.robot
|
||||
Resource Harbor-Pages/Robot_Account.robot
|
||||
Resource Harbor-Pages/Robot_Account_Elements.robot
|
||||
Resource Harbor-Pages/Verify.robot
|
||||
Resource Docker-Util.robot
|
||||
Resource CNAB_Util.robot
|
||||
|
@ -756,3 +756,27 @@ Test Case - P2P Preheat Policy CRUD
|
||||
Delete A Distribution ${dist_name} ${endpoint}
|
||||
Close Browser
|
||||
|
||||
Test Case - System Robot Account Cover All Projects
|
||||
[Tags] sys_robot_account_cover
|
||||
${d}= Get Current Date result_format=%m%s
|
||||
${pro_name}= Set Variable project_${d}
|
||||
Init Chrome Driver
|
||||
Sign In Harbor ${HARBOR_URL} ${HARBOR_ADMIN} ${HARBOR_PASSWORD}
|
||||
Create An New Project And Go Into Project ${pro_name}
|
||||
${name}= Create A New System Robot Account is_cover_all=${true}
|
||||
Navigate To Projects
|
||||
Switch To Robot Account
|
||||
System Robot Account Exist ${name} All
|
||||
Close Browser
|
||||
|
||||
Test Case - System Robot Account
|
||||
[Tags] sys_robot_account
|
||||
${d}= Get Current Date result_format=%m%s
|
||||
${project_count}= Evaluate random.randint(3, 5)
|
||||
${pro_name}= Set Variable project_${d}
|
||||
Init Chrome Driver
|
||||
Sign In Harbor ${HARBOR_URL} ${HARBOR_ADMIN} ${HARBOR_PASSWORD}
|
||||
${project_permission_list}= Create A Random Project Permission List ${project_count}
|
||||
${name}= Create A New System Robot Account project_permission_list=${project_permission_list}
|
||||
System Robot Account Exist ${name} ${project_count}
|
||||
Close Browser
|
||||
|
Loading…
Reference in New Issue
Block a user