def open_pyrobot(arglist, opt_arg=""): seleniumlib = BuiltIn().get_library_instance('Selenium2Library') if hasattr(arglist, 'lower'): print '(open_pybot) solo' if opt_arg == "": target_browser = os.environ[envname_pyrobot_default_browser] else: if not opt_arg in SELENIUM2LIB_BROWSERS: raise ValueError(opt_arg + " is not a supported browser.") target_browser = opt_arg print '%s (%s)' % (arglist, opt_arg) seleniumlib.open_browser(arglist, browser=target_browser) else: print '(open_pybot) sauce' if opt_arg == "": url = arglist[0] elif "http" in opt_arg: url = opt_arg else: raise ValueError(opt_arg + " is not a valid url.") print '[%s] url(%s)' % (', '.join(map(str, arglist)), url) seleniumlib.open_browser(url, browser=os.environ[envname_pyrobot_default_browser], remote_url=arglist[2], desired_capabilities=arglist[3]) # def open_browser(url, browser=None, remote=None, caps=None): # seleniumlib = BuiltIn().get_library_instance('Selenium2Library') # seleniumlib.open_browser(url, remote_url=remote, desired_capabilities=caps)
def report_sauce_status(name, status, tags=[], remote_url=''): # Parse username and access_key from the remote_url assert USERNAME_ACCESS_KEY.match(remote_url), 'Incomplete remote_url.' username, access_key = USERNAME_ACCESS_KEY.findall(remote_url)[0][1:] # Get selenium session id from the keyword library selenium = BuiltIn().get_library_instance('Selenium2Library') job_id = selenium._current_browser().session_id # Prepare payload and headers token = (':'.join([username, access_key])).encode('base64').strip() payload = {'name': name, 'passed': status == 'PASS', 'tags': tags} headers = {'Authorization': 'Basic {0}'.format(token)} # Put test status to Sauce Labs url = 'https://saucelabs.com/rest/v1/{0}/jobs/{1}'.format(username, job_id) response = requests.put(url, data=json.dumps(payload), headers=headers) assert response.status_code == 200, response.text # Log video url from the response video_url = json.loads(response.text).get('video_url') if video_url: logger.info('<a href="{0}">video.flv</a>'.format(video_url), html=True)
def is_element_present(self, locator): """Same than Page Should Contain Element but returns a boolean """ selenium2lib = BuiltIn().get_library_instance('Selenium2Library') try: return selenium2lib.page_should_contain_element(locator) except AssertionError: return False
def autologin_logout(self): """Logout a user that has been logged in by the autologin_as keyword. """ selenium2lib = BuiltIn().get_library_instance('Selenium2Library') selenium2lib.execute_javascript( "document.cookie = 'autologin=;path=/;domain=localhost;';" )
def input_value_on_next_prompt(self, value=None): """模拟prompt窗口输入value后点击ok的情况,同时记录窗口中的message。 不输入value参数时,则模拟prompt窗口在默认值情况下被点击ok的情况。 当页面存在window.prompt()时,必须在prompt窗口出现前使用该关键字。 每次有新页面加载之后必须重新调用这个关键字才会生效。 """ s2l = BuiltIn().get_library_instance('Selenium2Library') if value is None: js = """ window.prompt = function(message, defaultValue) { lastPopupMessage = message; return defaultValue; } """ s2l.execute_javascript('%s' % js) else: js_prefix = """ window.prompt = function(message, defaultValue) { lastPopupMessage = message; return '""" js_suffix = "';}" s2l.execute_javascript('%s%s%s' % (js_prefix, value, js_suffix))
class CapwapLibrary(object): """Provide many methods to simulate WTPs and their functions.""" def __init__(self): self.builtin = BuiltIn() def send_discover(self, ac_ip, wtp_ip='', ip='ip', port=5246): """Send Discover CAPWAP Packet from a WTP.""" data = ''.join(chr(x) for x in [0x00, 0x20, 0x01, 0x02, 0x03, 0x04, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]) self.builtin.log('Sending Discover Packet to: %s' % ac_ip, 'DEBUG') session = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) session.sendto(data, (ac_ip, port)) self.builtin.log('Packet Sent', 'DEBUG') def get_hostip(self): """Get Host IP Address.""" ip_addr = socket.gethostbyname(socket.gethostname()) return ip_addr def get_simulated_wtpip(self, controller): """Get the Simulated WTP ip based on the controller.""" if controller == '127.0.0.1': exp_ip = controller else: exp_ip = self.get_hostip() return exp_ip
def capture_and_mask_page_screenshot(self, filename, locators=None, rects=None): ''' Captures page screenshot and masks specified element. ''' s2l = BuiltIn().get_library_instance('Selenium2Library') # note: filename is required because otherwise we don't have reference to # auto-generated filename s2l.capture_page_screenshot(filename) rectangles = [] for locator in locators or []: element = s2l._element_find(locator, True, False) if element is None: raise AssertionError("Could not locate element for '%s'" % (locator)) x, y = element.location['x'], element.location['y'] w, h = element.size['width'], element.size['height'] rectangles.append([x, y, x+w, y+h]) for rect in rects or []: try: x, y, w, h = [int(i) for i in rect.split(',')] rectangles.append([x, y, x+w, y+h]) except: raise AssertionError("Could not locate rectangle for '%s'" % (rect)) self.mask_image(filename, rectangles)
def is_visible(self, locator): """Same than Element Should Be Visible but returns a boolean """ selenium2lib = BuiltIn().get_library_instance('Selenium2Library') try: return selenium2lib.element_should_be_visible(locator) except AssertionError: return False
def test_log_directory(): """This function will create case log directory for saving TA log when you call it firstly. If you want to save or use TA log, you must call this keyword on your TA case. """ global TEST_CASE_NAME global TEST_LOG_PATH try: test_case_name = BuiltIn().get_variables()['${TEST_NAME}'] except: try: test_case_name = BuiltIn().get_variables()['${SUITE_NAME}'] except: test_case_name = "mt_case_name" test_case_name = test_case_name.strip().replace(" ", "_") if TEST_CASE_NAME != test_case_name: try: output_dir = BuiltIn().get_variables()['${OUTPUT_DIR}'] except: output_dir = "mt_output_dir" test_suite_path = os.path.join(output_dir, "log") TEST_CASE_NAME = test_case_name test_name_with_timestamp = test_case_name + "_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + "/" test_log_directory = os.path.join(test_suite_path, test_name_with_timestamp) TEST_LOG_PATH = test_log_directory if not os.path.exists(TEST_LOG_PATH): os.makedirs(TEST_LOG_PATH) return TEST_LOG_PATH
def demo_title_should_be(self,expected): # a demo by YT for implemnting the same function as 'Title Should Be' seleniumlib = BuiltIn().get_library_instance('Selenium2Library') title = seleniumlib.get_title() if not title.startswith(expected): raise AssertionError("Title '%s' did not start with '%s'" % (title, expected))
def report_sauce_status(name, status): selenium = BuiltIn().get_library_instance('Selenium2Library') job_id = selenium._current_browser().session_id passed = status == 'PASS' sauce_client.jobs.update_job(job_id, passed = passed, name = name) sessionId = "SauceOnDemandSessionID=%s job-name=%s" % (job_id, name) print sessionId return sessionId
def get_items_in_context_menu(self, locator): """Returns the text from the context menu located by 'locator' """ selenium = BuiltIn().get_library_instance("Selenium2Library") return selenium.execute_javascript( "return document.getElementById('dashMenu_4').getElementsByTagName'div')[1].getElementsByClassName('rich-menu-item rich-menu-item-enabled')[" + str(locator) + "].getElementsByTagName('span')[1].textContent" )
def get_element_text(self, element, child): """Returns the text found at the 'child' of the 'element' """ selenium = BuiltIn().get_library_instance("Selenium2Library") id = selenium.get_element_attribute(element + "@id") print "id:" + str(id) return selenium.execute_javascript( 'return document.getElementById("' + id + '").childNodes[' + str(child) + "].textContent" )
def get_columnvalues(self,table_locator,columnName,icount): selenium = BuiltIn().get_library_instance('Selenium2Library') columnNo = int(self.table_get_column_no(table_locator,columnName)) list1=[] for iRow in range(4,15): list2=selenium.get_text('//span[contains(text(),"Available Students")]//following::div//div//table//th[5]//following::div['+str(iRow)+']//table//td['+str(columnNo)+']') list1.append(list2) return list1
def report_saucelabs_status(name, status, tags=[], remote_url=''): # Parse username and access_key from the remote_url assert USERNAME_ACCESS_KEY.match(remote_url), 'Incomplete remote_url.' username, access_key = USERNAME_ACCESS_KEY.findall(remote_url)[0][1:] # Get selenium session id from the keyword library selenium = BuiltIn().get_library_instance('Selenium2Library') job_id = selenium._current_browser().session_id
def press_control_and_key(self,locator,key): """Presses the control Key and Specified key 'key' at element located by the 'locator' """ selenium = BuiltIn().get_library_instance('Selenium2Library') loc = selenium._element_find(locator,True,True) loc.send_keys(Keys.CONTROL, 'a') time.sleep(1) loc.send_keys(Keys.CONTROL,key) time.sleep(1)
def close_alert_message(self): """Returns 'True'if any alert message displayed returns 'False' if not""" selenium = BuiltIn().get_library_instance('Selenium2Library') try: selenium.get_alert_message() return True except: return False
class Initting(object): def __init__(self): # This initializes the accesses library. self.lib = BuiltIn().get_library_instance("InitImportingAndIniting.Initted") def kw_from_lib_with_initting_init(self): logger.info("Keyword from library with initting __init__.") self.lib.kw_from_lib_initted_by_init()
def App_Verify_Alert_Present(): seleniumlib = BuiltIn().get_library_instance('Selenium2Library') try: alert=seleniumlib._current_browser().switch_to_alert() text = ' '.join(alert.text.splitlines()) return True except: return False
def write_to_stdin(process_handle, text): lib = BuiltIn().get_library_instance('Process') obj = lib.get_process_object() obj.stdin.write(text + "\n") obj.stdin.flush() obj.stdin.close() out = obj.stdout.read(4096) return out
def select_window_by_title(self,windowtitle): """Select a window by window title""" selenium = BuiltIn().get_library_instance('Selenium2Library') #browser = selenium._current_browser() windows=selenium.get_window_titles() for window in windows: if window==windowtitle: selenium.select_window(window)
def __init__(self): self._logger = logger try: se2lib = BuiltIn().get_library_instance('Selenium2Library') self.driver=se2lib._current_browser() self.logMsg('DEBUG UI OPEN: '+self.driver.current_url) # Show a message in the robotframework log except: self.driver=None
def click_the_nth_element(locator,index): """Returns the nth elements of all WebElement objects matching locator. See `introduction` for details about locating elements. """ seleniumlib = BuiltIn().get_library_instance('Selenium2Library') found_elements=seleniumlib.get_webelements(locator) found_elements[int(index)].click() return found_elements[int(index)]
def select_the_row(self, table_locator, rowNo): "Returns the text located in the table 'table_locator' with in the Column 'columnName' and matching Row 'iRowNo'" "" selenium = BuiltIn().get_library_instance("Selenium2Library") return selenium.click_element( table_locator + '/div[@class="dgrid-scroller"]/div[contains(@class,"dgrid-content")]//div[contains(@id,"-row")][' + str(rowNo) + "]" )
def _get_opts_from_robot(self): """ Pulls environment from PO_ environment file """ ret = {} robot_vars = BuiltIn().get_variables() for var, val in robot_vars.iteritems(): ret[self._normalize(var)] = val return ret
def demo_input_text(self,locator,text): # a demo by YT for implemnting the same function as 'Input Text' """Description: Types the given `text` into text field identified by `locator`. See `introduction` for details about locating elements. """ appiumlib = BuiltIn().get_library_instance('SongzAppiumLibrary') appiumlib._info("Typing text '%s' into text field '%s'" % (text, locator)) appiumlib._element_input_text_by_locator(locator, text)
def get_alert_message(self): """Returns 'True'if any alert message displayed returns 'False' if not""" selenium = BuiltIn().get_library_instance('Selenium2Library') text = '' try: text=selenium.get_alert_message() return [True,text] except: return [False,text]
def wait_for_element_visible(self,locator,timeout=None,messgae=''): if(timeout == None): timeout = "30s" selenium = BuiltIn().get_library_instance('Selenium2Library') for iCounter in range(1,3): selenium.wait_until_page_contains_element(locator,timeout) selenium.wait_until_element_is_visible(locator,timeout) return true
def autologin_as(self, username, password): """Autologin as Django user. DjangoLibrary comes with a Django middleware component that allows the autologin_as keyword to set an 'autologin' cookie that the middleware uses to authenticate and login the user in Django. If you want to use the autlogin_as keyword you have to add 'DjangoLibrary.middleware.AutologinAuthenticationMiddleware' to the MIDDLEWARE_CLASSES right after the default AuthenticationMiddleware in your settings.py:: MIDDLEWARE_CLASSES = ( ... 'django.contrib.auth.middleware.AuthenticationMiddleware', 'DjangoLibrary.middleware.AutologinAuthenticationMiddleware', ) *Warning* Make sure that you add this middleware only to your test setup and NEVER to your deployment! See https://github.com/kitconcept/robotframework-djangolibrary/blob/master/DjangoLibrary/tests/test_autologin.robot # noqa for examples how to use the `Autologin As` keyword. """ if six.PY2: username = username.encode('utf-8') password = password.encode('utf-8') # encode autologin cookie value as base64 autologin_cookie_value = base64.b64encode( safe_bytes("%s:%s" % (username, password)) ) selenium2lib = BuiltIn().get_library_instance('Selenium2Library') # XXX: The 'Add Cookie' keywords does not work with Firefox, therefore # we have to add the cookie with js here. A bug has been filed: # https://github.com/rtomac/robotframework-selenium2library/issues/273 # selenium2lib.add_cookie( # "autologin", # "%s:%s" % (username, password), # path="/", # domain="localhost", # ) if six.PY3: selenium2lib.execute_javascript( "document.cookie = 'autologin=%s;path=/;domain=localhost;';" % autologin_cookie_value.decode('utf-8') ) else: selenium2lib.execute_javascript( "document.cookie = 'autologin=%s;path=/;domain=localhost;';" % autologin_cookie_value )
def demo_get_size(self,locator): # not implement yet driver = self._current_application() appiumlib = BuiltIn().get_library_instance('SongzAppiumLibrary') appiumlib.get_window_size()['width'] appiumlib.get_window_size()['height'] pass
def add(self, dev1, intf1, dev2, intf2, direction='bi', force=False): """ Adds x-connection between ``dev1:intf1`` and ``dev2:intf2`` ``direction`` is ``bi`` for bi-direction or ``uni`` for uni-direction. If ``direction`` is ``uni``, the tx of ``dev 1:port 1`` will be connected to ``dev 2:port 2``. With ``force`` mode, existed connection that use those ports will be deleted. Without ``force`` mode, an existed connection will make the keyword fails Examples: | OpticalSwitch.`Add` | mx2008-31-33 | xe-3/0/0 | mx2008-31-33 | xe-3/0/1 | bi | ${TRUE} | *Note*: when ``force`` is ``False`` but the current ports is owned by the same connection endpoints, keyword will succeed. For a bidirection connection, 2 single uni-direction connection will be made instead of 1 bi-direction connection. This will make the link could be simulated tx/rx failure later. """ BuiltIn().log("Adds %s connection %s:%s %s:%s" % (direction, dev1, intf1, dev2, intf2)) switch = '' conn_id = '' port1 = '' port2 = '' result = False conn_info = _make_conn_info(self, dev1, intf1, dev2, intf2, direction) if conn_info: switch = conn_info[0] conn_id = conn_info[1] port1 = conn_info[2] port2 = conn_info[3] else: return False cli = self._clients[switch] ip = cli['ip'] session = cli['session'] # delete existed connection in Force mode if force: _delete_conn_info(self, switch, port1, port2, direction) else: tmp1 = _get_circuit_from_port(self, switch, port1, ['incircuit', 'outcircuit']) tmp2 = _get_circuit_from_port(self, switch, port2, ['incircuit', 'outcircuit']) # circuits = list(set(tmp1 + tmp2)) used_port = [] for item in (tmp1 + tmp2): for i in re.split(r'<|>', item): if not i in used_port: used_port.append(i) if used_port and (sorted([port1, port2]) != sorted(used_port)): raise Exception("Ports are being used: %s:%s by %s, %s:%s by %s" % (dev1, intf1, str(tmp1), dev2, intf2, str(tmp2))) else: _delete_conn_info(self, switch, port1, port2, direction) BuiltIn().log(" deleted old circuits because same owner") if direction.lower() == 'bi': rest_result1 = session.post('http://' + ip + '/rest/crossconnects/', data={ 'id': 'add', 'in': port1, 'out': port2, 'dir': 'uni' }) rest_result2 = session.post('http://' + ip + '/rest/crossconnects/', data={ 'id': 'add', 'in': port2, 'out': port1, 'dir': 'uni' }) if rest_result1.status_code == requests.codes.ok and rest_result2.status_code == requests.codes.ok: result = True msg1 = rest_result1.json()[0]['msg'] desc1 = rest_result1.json()[0]['description'] msg2 = rest_result2.json()[0]['msg'] desc2 = rest_result2.json()[0]['description'] # BuiltIn().log("Result: msg1 = %s, desc1 = %s" % (msg1,desc1)) # BuiltIn().log("Result: msg2 = %s, desc2 = %s" % (msg2,desc2)) if rest_result1.json()[0]['status'] == "1" and rest_result2.json( )[0]['status'] == "1": result = True BuiltIn().log( "Added connection %s on switch %s, connects %s:%s - %s:%s" % (conn_id, switch, dev1, intf1, dev2, intf2)) else: result = False raise Exception( "Failed to add a binary x-connection (%s,%s)(%s,%s)" % (msg1, desc1, msg2, desc2)) else: result = False raise Exception( "REST API failed (%d,%d) while trying to add a binary x-connection" % (rest_result1.status_code, rest_result2.status_code)) else: rest_result = session.post('http://' + ip + '/rest/crossconnects/', data={ 'id': 'add', 'in': port1, 'out': port2, 'dir': 'uni' }) if rest_result.status_code == requests.codes.ok: result = True msg = rest_result.json()[0]['msg'] desc = rest_result.json()[0]['description'] BuiltIn().log("Result: msg = %s, desc = %s" % (msg, desc)) if rest_result.json()[0]['status'] == "1": result = True BuiltIn().log( "Added connection %s on switch %s, connects %s:%s > %s:%s" % (conn_id, switch, dev1, port1, dev2, port2)) else: result = False raise Exception("Failed to add a uni x-connection (%s,%s)" % (msg, desc)) else: result = False raise Exception( "REST API failed (%d) while truing to an uni add x-connction" % (rest_result.status_code)) return result
from robot.api import logger from robot.api.deco import keyword from robot.libraries.BuiltIn import BuiltIn should_be_equal = BuiltIn().should_be_equal log = logger.write @keyword(name="User ${user} Selects ${item} From Webshop") def user_selects_from_webshop(user, item): log("This is always executed") return user, item @keyword( name= "${prefix:Given|When|Then} this \"${item}\" ${no good name for this arg ...}" ) def this(ignored_prefix, item, somearg): log("%s-%s" % (item, somearg)) @keyword(name="My embedded ${var}") def my_embedded(var): should_be_equal(var, "warrior") @keyword(name="${x:x} gets ${y:\w} from the ${z:.}") def gets_from_the(x, y, z): should_be_equal("%s-%s-%s" % (x, y, z), "x-y-z")
def delete(self, dev1, intf1, dev2, intf2, direction='bi', force=False): """ Deletes the connection between ``dev1:intf1 - dev2:intf2`` Examples: | OpticalSwitch.`Delete` | mx2008-31-33 | xe-3/0/1 | mx2008-31-33 | xe-3/0/1 | uni | """ switch = '' conn_id = '' port1 = '' port2 = '' conn_info = _make_conn_info(self, dev1, intf1, dev2, intf2) if conn_info: switch = conn_info[0] conn_id = conn_info[1] port1 = conn_info[2] port2 = conn_info[3] else: return False cli = self._clients[switch] ip = cli['ip'] session = cli['session'] result = False ## make uniq list if direction.lower() == "bi": tmp1 = _get_circuit_from_port(self, switch, port1, ['incircuit', 'outcircuit']) tmp2 = _get_circuit_from_port(self, switch, port2, ['incircuit', 'outcircuit']) circuits = list(set(tmp1 + tmp2)) else: tmp1 = _get_circuit_from_port(self, switch, port1, ['incircuit']) tmp2 = _get_circuit_from_port(self, switch, port2, ['outcircuit']) circuits = list(set(tmp1 + tmp2)) if len(circuits) == 0: BuiltIn().log("The connection is not valid") for item in circuits: rest_result = session.delete('http://' + ip + '/rest/crossconnects/?conn=' + item) if rest_result.status_code == requests.codes.ok: stat = rest_result.json()[0]['status'] msg = rest_result.json()[0]['msg'] desc = rest_result.json()[0]['description'] BuiltIn().log("Result: status = %s, msg = %s, desc = %s" % (stat, msg, desc)) if stat == "1": result = True BuiltIn().log("Deleted connection %s on switch %s" % (item, switch)) else: result = False raise Exception("Failed to make the connection(%d,%s,%s)" % (rest_result.status_code, msg, desc)) break else: result = False raise Exception("Failed to delete the connection %s (%d)" % (item, rest_result.status_code)) break return result
import requests from robot.libraries.BuiltIn import BuiltIn, RobotNotRunningError from RPA.Browser.Selenium import Selenium from RPA.RobotLogListener import RobotLogListener try: from importlib import import_module import importlib.resources as pkg_resources except ImportError: # Try backported to PY<37 `importlib_resources`. import importlib_resources as pkg_resources try: BuiltIn().import_library("RPA.RobotLogListener") except RobotNotRunningError: pass class Handler(BaseHTTPRequestHandler): """Server request handler class""" # pylint: disable=unused-argument, signature-differs def log_message(self, *args, **kwargs): return # pylint: disable=unused-argument, signature-differs def log_request(self, *args, **kwargs): pass
def _connect_to_amqp(self, host, port, username='******', password='******', alias=None, virtual_host='/', socket_timeout=400, heartbeat_timeout=600, blocked_timeout=300): """ Connect to server via AMQP. *Args*:\n _host_: server host name.\n _port_: port number.\n _username_: user name.\n _password_: user password.\n _alias_: connection alias.\n _virtual_host_: virtual host name;\n _socket_timeout_: socket connect timeout;\n _heartbeat_timeout_: AMQP heartbeat timeout negotiation during connection tuning;\n _blocked_timeout_: timeout for the connection to remain blocked.\n *Returns:*\n Server connection object. """ if port is None: BuiltIn().fail(msg="RabbitMq: port for connect is None") port = int(port) if virtual_host is None: BuiltIn().fail(msg="RabbitMq: virtual host for connect is None") virtual_host = str(virtual_host) parameters_for_connect = "host={host}, port={port}, username={username}, timeout={timeout}, alias={alias}".format( host=host, port=port, username=username, timeout=socket_timeout, alias=alias) #logger.debug('Connecting using : {params}'.format(params=parameters_for_connect)) credentials = pika.PlainCredentials(username=username, password=password) parameters = pika.URLParameters( 'amqp://{username}:{password}@host:5672/%2F') conn_params = pika.ConnectionParameters( host=host, port=port, credentials=credentials, virtual_host=virtual_host, socket_timeout=socket_timeout, blocked_connection_timeout=blocked_timeout, heartbeat=heartbeat_timeout) logger.debug('Connecting using : {params}'.format(params=parameters)) try: self._amqp_connection = BlockedConnection(parameters=parameters) except (gaierror, error, IOError, IncompatibleProtocolError): BuiltIn().fail( msg= "RabbitMq: Could not connect with following parameters: {params}" .format(params=parameters_for_connect)) self._channel = None return self._amqp_cache.register(self._amqp_connection, alias)
class _ElementKeywords(KeywordGroup): def __init__(self): self._element_finder = ElementFinder() self._bi = BuiltIn() # Public, element lookups def clear_text(self, locator): """Clears the text field identified by `locator`. See `introduction` for details about locating elements. """ self._info("Clear text field '%s'" % locator) self._element_clear_text_by_locator(locator) def click_element(self, locator): """Click element identified by `locator`. Key attributes for arbitrary elements are `index` and `name`. See `introduction` for details about locating elements. """ self._info("Clicking element '%s'." % locator) self._element_find(locator, True, True).click() def click_button(self, index_or_name): """ Click button """ _platform_class_dict = { 'ios': 'UIAButton', 'android': 'android.widget.Button' } if self._is_support_platform(_platform_class_dict): class_name = self._get_class(_platform_class_dict) self._click_element_by_class_name(class_name, index_or_name) def click_text(self, text, exact_match=False): """Click text identified by ``text``. By default tries to click first text involves given ``text``, if you would like to click exactly matching text, then set ``exact_match`` to `True`. If there are multiple use of ``text`` and you do not want first one, use `locator` with `Get Web Elements` instead. """ self._element_find_by_text(text, exact_match).click() def input_text(self, locator, text): """Types the given `text` into text field identified by `locator`. See `introduction` for details about locating elements. """ self._info("Typing text '%s' into text field '%s'" % (text, locator)) self._element_input_text_by_locator(locator, text) def input_password(self, locator, text): """Types the given password into text field identified by `locator`. Difference between this keyword and `Input Text` is that this keyword does not log the given password. See `introduction` for details about locating elements. """ self._info("Typing password into text field '%s'" % locator) self._element_input_text_by_locator(locator, text) def input_value(self, locator, text): """Sets the given value into text field identified by `locator`. This is an IOS only keyword, input value makes use of set_value See `introduction` for details about locating elements. """ self._info("Setting text '%s' into text field '%s'" % (text, locator)) self._element_input_value_by_locator(locator, text) def hide_keyboard(self, key_name=None): """Hides the software keyboard on the device. (optional) In iOS, use `key_name` to press a particular key, ex. `Done`. In Android, no parameters are used. """ driver = self._current_application() driver.hide_keyboard(key_name) def page_should_contain_text(self, text, loglevel='INFO'): """Verifies that current page contains `text`. If this keyword fails, it automatically logs the page source using the log level specified with the optional `loglevel` argument. Giving `NONE` as level disables logging. """ if not self._is_text_present(text): self.log_source(loglevel) raise AssertionError("Page should have contained text '%s' " "but did not" % text) self._info("Current page contains text '%s'." % text) def page_should_not_contain_text(self, text, loglevel='INFO'): """Verifies that current page not contains `text`. If this keyword fails, it automatically logs the page source using the log level specified with the optional `loglevel` argument. Giving `NONE` as level disables logging. """ if self._is_text_present(text): self.log_source(loglevel) raise AssertionError("Page should not have contained text '%s'" % text) self._info("Current page does not contains text '%s'." % text) def page_should_contain_element(self, locator, loglevel='INFO'): """Verifies that current page contains `locator` element. If this keyword fails, it automatically logs the page source using the log level specified with the optional `loglevel` argument. Giving `NONE` as level disables logging. """ if not self._is_element_present(locator): self.log_source(loglevel) raise AssertionError("Page should have contained element '%s' " "but did not" % locator) self._info("Current page contains element '%s'." % locator) def page_should_not_contain_element(self, locator, loglevel='INFO'): """Verifies that current page not contains `locator` element. If this keyword fails, it automatically logs the page source using the log level specified with the optional `loglevel` argument. Giving `NONE` as level disables logging. """ if self._is_element_present(locator): self.log_source(loglevel) raise AssertionError( "Page should not have contained element '%s'" % locator) self._info("Current page not contains element '%s'." % locator) def element_should_be_disabled(self, locator, loglevel='INFO'): """Verifies that element identified with locator is disabled. Key attributes for arbitrary elements are `id` and `name`. See `introduction` for details about locating elements. """ if self._element_find(locator, True, True).is_enabled(): self.log_source(loglevel) raise AssertionError("Element '%s' should be disabled " "but did not" % locator) self._info("Element '%s' is disabled ." % locator) def element_should_be_enabled(self, locator, loglevel='INFO'): """Verifies that element identified with locator is enabled. Key attributes for arbitrary elements are `id` and `name`. See `introduction` for details about locating elements. """ if not self._element_find(locator, True, True).is_enabled(): self.log_source(loglevel) raise AssertionError("Element '%s' should be enabled " "but did not" % locator) self._info("Element '%s' is enabled ." % locator) def element_should_be_visible(self, locator, loglevel='INFO'): """Verifies that element identified with locator is visible. Key attributes for arbitrary elements are `id` and `name`. See `introduction` for details about locating elements. New in AppiumLibrary 1.4.5 """ if not self._element_find(locator, True, True).is_displayed(): self.log_source(loglevel) raise AssertionError("Element '%s' should be visible " "but did not" % locator) def element_name_should_be(self, locator, expected): element = self._element_find(locator, True, True) if str(expected) != str(element.get_attribute('name')): raise AssertionError( "Element '%s' name should be '%s' " "but it is '%s'." % (locator, expected, element.get_attribute('name'))) self._info("Element '%s' name is '%s' " % (locator, expected)) def element_value_should_be(self, locator, expected): element = self._element_find(locator, True, True) if str(expected) != str(element.get_attribute('value')): raise AssertionError( "Element '%s' value should be '%s' " "but it is '%s'." % (locator, expected, element.get_attribute('value'))) self._info("Element '%s' value is '%s' " % (locator, expected)) def element_attribute_should_match(self, locator, attr_name, match_pattern, regexp=False): """Verify that an attribute of an element matches the expected criteria. The element is identified by _locator_. See `introduction` for details about locating elements. If more than one element matches, the first element is selected. The _attr_name_ is the name of the attribute within the selected element. The _match_pattern_ is used for the matching, if the match_pattern is - boolean or 'True'/'true'/'False'/'false' String then a boolean match is applied - any other string is cause a string match The _regexp_ defines whether the string match is done using regular expressions (i.e. BuiltIn Library's [http://robotframework.org/robotframework/latest/libraries/BuiltIn.html#Should%20Match%20Regexp|Should Match Regexp] or string pattern match (i.e. BuiltIn Library's [http://robotframework.org/robotframework/latest/libraries/BuiltIn.html#Should%20Match|Should Match]) Examples: | Element Attribute Should Match | xpath = //*[contains(@text,'foo')] | text | *foobar | | Element Attribute Should Match | xpath = //*[contains(@text,'foo')] | text | f.*ar | regexp = True | | Element Attribute Should Match | xpath = //*[contains(@text,'foo')] | enabled | True | | 1. is a string pattern match i.e. the 'text' attribute should end with the string 'foobar' | 2. is a regular expression match i.e. the regexp 'f.*ar' should be within the 'text' attribute | 3. is a boolead match i.e. the 'enabled' attribute should be True _*NOTE: *_ On Android the supported attribute names are hard-coded in the [https://github.com/appium/appium/blob/master/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/AndroidElement.java|AndroidElement] Class's getBoolAttribute() and getStringAttribute() methods. Currently supported (appium v1.4.11): _contentDescription, text, className, resourceId, enabled, checkable, checked, clickable, focusable, focused, longClickable, scrollable, selected, displayed_ _*NOTE: *_ Some attributes can be evaluated in two different ways e.g. these evaluate the same thing: | Element Attribute Should Match | xpath = //*[contains(@text,'example text')] | name | txt_field_name | | Element Name Should Be | xpath = //*[contains(@text,'example text')] | txt_field_name | | """ elements = self._element_find(locator, False, True) if len(elements) > 1: self._info( "CAUTION: '%s' matched %s elements - using the first element only" % (locator, len(elements))) attr_value = elements[0].get_attribute(attr_name) # ignore regexp argument if matching boolean if isinstance(match_pattern, bool) or match_pattern.lower( ) == 'true' or match_pattern.lower() == 'false': if isinstance(match_pattern, bool): match_b = match_pattern else: match_b = ast.literal_eval(match_pattern.title()) if isinstance(attr_value, bool): attr_b = attr_value else: attr_b = ast.literal_eval(attr_value.title()) self._bi.should_be_equal(match_b, attr_b) elif regexp: self._bi.should_match_regexp( attr_value, match_pattern, msg="Element '%s' attribute '%s' should have been '%s' " "but it was '%s'." % (locator, attr_name, match_pattern, attr_value), values=False) else: self._bi.should_match( attr_value, match_pattern, msg="Element '%s' attribute '%s' should have been '%s' " "but it was '%s'." % (locator, attr_name, match_pattern, attr_value), values=False) # if expected != elements[0].get_attribute(attr_name): # raise AssertionError("Element '%s' attribute '%s' should have been '%s' " # "but it was '%s'." % (locator, attr_name, expected, element.get_attribute(attr_name))) self._info("Element '%s' attribute '%s' is '%s' " % (locator, attr_name, match_pattern)) def element_should_contain_text(self, locator, expected, message=''): """Verifies element identified by ``locator`` contains text ``expected``. If you wish to assert an exact (not a substring) match on the text of the element, use `Element Text Should Be`. Key attributes for arbitrary elements are ``id`` and ``xpath``. ``message`` can be used to override the default error message. New in AppiumLibrary 1.4. """ self._info("Verifying element '%s' contains text '%s'." % (locator, expected)) actual = self._get_text(locator) if not expected in actual: if not message: message = "Element '%s' should have contained text '%s' but "\ "its text was '%s'." % (locator, expected, actual) raise AssertionError(message) def element_should_not_contain_text(self, locator, expected, message=''): """Verifies element identified by ``locator`` does not contain text ``expected``. ``message`` can be used to override the default error message. See `Element Should Contain Text` for more details. """ self._info("Verifying element '%s' does not contain text '%s'." % (locator, expected)) actual = self._get_text(locator) if expected in actual: if not message: message = "Element '%s' should not contain text '%s' but " \ "it did." % (locator, expected) raise AssertionError(message) def element_text_should_be(self, locator, expected, message=''): """Verifies element identified by ``locator`` exactly contains text ``expected``. In contrast to `Element Should Contain Text`, this keyword does not try a substring match but an exact match on the element identified by ``locator``. ``message`` can be used to override the default error message. New in AppiumLibrary 1.4. """ self._info("Verifying element '%s' contains exactly text '%s'." % (locator, expected)) element = self._element_find(locator, True, True) actual = element.text if expected != actual: if not message: message = "The text of element '%s' should have been '%s' but "\ "in fact it was '%s'." % (locator, expected, actual) raise AssertionError(message) def get_webelement(self, locator): """Returns the first [http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.remote.webelement|WebElement] object matching ``locator``. Example: | ${element} | Get Webelement | id=my_element | | Click Element | ${element} | | New in AppiumLibrary 1.4. """ return self._element_find(locator, True, True) def get_webelements(self, locator): """Returns list of [http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.remote.webelement|WebElement] objects matching ``locator``. Example: | @{elements} | Get Webelements | id=my_element | | Click Element | @{elements}[2] | | This keyword was changed in AppiumLibrary 1.4 in following ways: - Name is changed from `Get Elements` to current one. - Deprecated argument ``fail_on_error``, use `Run Keyword and Ignore Error` if necessary. New in AppiumLibrary 1.4. """ return self._element_find(locator, False, True) def get_element_attribute(self, locator, attribute): """Get element attribute using given attribute: name, value,... Examples: | Get Element Attribute | locator | name | | Get Element Attribute | locator | value | """ elements = self._element_find(locator, False, True) ele_len = len(elements) if ele_len == 0: raise AssertionError("Element '%s' could not be found" % locator) elif ele_len > 1: self._info( "CAUTION: '%s' matched %s elements - using the first element only" % (locator, len(elements))) try: attr_val = elements[0].get_attribute(attribute) self._info("Element '%s' attribute '%s' value '%s' " % (locator, attribute, attr_val)) return attr_val except: raise AssertionError( "Attribute '%s' is not valid for element '%s'" % (attribute, locator)) def get_element_location(self, locator): """Get element location Key attributes for arbitrary elements are `id` and `name`. See `introduction` for details about locating elements. """ element = self._element_find(locator, True, True) element_location = element.location self._info("Element '%s' location: %s " % (locator, element_location)) return element_location def get_element_size(self, locator): """Get element size Key attributes for arbitrary elements are `id` and `name`. See `introduction` for details about locating elements. """ element = self._element_find(locator, True, True) element_size = element.size self._info("Element '%s' size: %s " % (locator, element_size)) return element_size def get_text(self, locator): """Get element text (for hybrid and mobile browser use `xpath` locator, others might cause problem) Example: | ${text} | Get Text | //*[contains(@text,'foo')] | New in AppiumLibrary 1.4. """ text = self._get_text(locator) self._info("Element '%s' text is '%s' " % (locator, text)) return text def get_matching_xpath_count(self, xpath): """Returns number of elements matching ``xpath`` One should not use the `xpath=` prefix for 'xpath'. XPath is assumed. | *Correct:* | | ${count} | Get Matching Xpath Count | //android.view.View[@text='Test'] | | Incorrect: | | ${count} | Get Matching Xpath Count | xpath=//android.view.View[@text='Test'] | If you wish to assert the number of matching elements, use `Xpath Should Match X Times`. New in AppiumLibrary 1.4. """ count = len(self._element_find("xpath=" + xpath, False, False)) return str(count) def get_matching_count(self, locator): """Returns number of elements matching ``xpath`` One should not use the `xpath=` prefix for 'xpath'. XPath is assumed. | Correct: | | ${count} | Get Matching Count | xpath=//android.view.View[@text='Test'] | | ${count} | Get Matching Count | id='Test' | If you wish to assert the number of matching elements, use `Should Match X Times`. `Should MAX X Times`. `Should MIN X Times`. New in AppiumLibrary 1.4. """ count = len(self._element_find(locator, False, False)) return str(count) def text_should_be_visible(self, text, exact_match=False, loglevel='INFO'): """Verifies that element identified with text is visible. New in AppiumLibrary 1.4.5 """ if not self._element_find_by_text(text, exact_match).is_displayed(): self.log_source(loglevel) raise AssertionError("Text '%s' should be visible " "but did not" % text) def xpath_should_match_x_times(self, xpath, count, error=None, loglevel='INFO'): """Verifies that the page contains the given number of elements located by the given ``xpath``. One should not use the `xpath=` prefix for 'xpath'. XPath is assumed. | *Correct:* | | Xpath Should Match X Times | //android.view.View[@text='Test'] | 1 | | Incorrect: | | Xpath Should Match X Times | xpath=//android.view.View[@text='Test'] | 1 | ``error`` can be used to override the default error message. See `Log Source` for explanation about ``loglevel`` argument. New in AppiumLibrary 1.4. """ actual_xpath_count = len( self._element_find("xpath=" + xpath, False, False)) if int(actual_xpath_count) != int(count): if not error: error = "Xpath %s should have matched %s times but matched %s times"\ %(xpath, count, actual_xpath_count) self.log_source(loglevel) raise AssertionError(error) self._info("Current page contains %s elements matching '%s'." % (actual_xpath_count, xpath)) def should_match_x_times(self, locator, count, error=None, loglevel='INFO'): """Verifies that the page contains the given number of elements located by the given ``xpath``. One should not use the `xpath=` prefix for 'xpath'. XPath is assumed. | *Correct:* | | Xpath Should Match X Times | //android.view.View[@text='Test'] | 1 | | Incorrect: | | Xpath Should Match X Times | xpath=//android.view.View[@text='Test'] | 1 | ``error`` can be used to override the default error message. See `Log Source` for explanation about ``loglevel`` argument. New in AppiumLibrary 1.4. """ actual_count = len(self._element_find(locator, False, False)) if int(actual_count) != int(count): if not error: error = "locator %s should have matched %s times but matched %s times"\ %(locator, count, actual_count) self.log_source(loglevel) raise AssertionError(error) self._info("Current page contains %s elements matching '%s'." % (actual_count, locator)) def should_max_x_times(self, locator, count, error=None, loglevel='INFO'): """Verifies that the page contains the given number of elements located by the given ``xpath``. One should not use the `xpath=` prefix for 'xpath'. XPath is assumed. | *Correct:* | | Xpath Should Match X Times | //android.view.View[@text='Test'] | 1 | | Incorrect: | | Xpath Should Match X Times | xpath=//android.view.View[@text='Test'] | 1 | ``error`` can be used to override the default error message. See `Log Source` for explanation about ``loglevel`` argument. New in AppiumLibrary 1.4. """ actual_xpath_count = len(self._element_find(locator, False, False)) if int(actual_xpath_count) <= int(count): if not error: error = "locator %s should have matched %s times but matched %s times"\ %(locator, count, actual_xpath_count) self.log_source(loglevel) raise AssertionError(error) self._info("Current page contains %s elements matching '%s'." % (actual_xpath_count, locator)) def should_min_x_times(self, locator, count, error=None, loglevel='INFO'): """Verifies that the page contains the given number of elements located by the given ``xpath``. One should not use the `xpath=` prefix for 'xpath'. XPath is assumed. | *Correct:* | | Xpath Should Match X Times | //android.view.View[@text='Test'] | 1 | | Incorrect: | | Xpath Should Match X Times | xpath=//android.view.View[@text='Test'] | 1 | ``error`` can be used to override the default error message. See `Log Source` for explanation about ``loglevel`` argument. New in AppiumLibrary 1.4. """ actual_xpath_count = len(self._element_find(locator, False, False)) if int(actual_xpath_count) >= int(count): if not error: error = "Xpath %s should have matched %s times but matched %s times"\ %(xpath, count, actual_xpath_count) self.log_source(loglevel) raise AssertionError(error) self._info("Current page contains %s elements matching '%s'." % (actual_xpath_count, locator)) def click_element_if_contain(self, locator, timeout=None): timeout = robot.utils.timestr_to_secs( timeout) if timeout is not None else self._timeout_in_secs maxtime = time.time() + timeout while True: ele = self._element_find(locator, True, False) if ele is not None: ele.click() self._info("Sucess Click the element %s " % locator) break if time.time() > maxtime: self._info("Can not Click the element %s " % locator) break time.sleep(0.2) def swipe_unitl_element_visable(self, locator, direct, timeout=30): timeout = robot.utils.timestr_to_secs( timeout) if timeout is not None else self._timeout_in_secs maxtime = time.time() + timeout while True: time.sleep(0.5) if self._is_visible(locator): self._info("the element %s is viable,and the direct is %s" % (locator, direct)) break else: if direct.lower() == 'up': self.swipe_by_percent(50, 80, 50, 30) elif direct.lower() == 'down': self.swipe_by_percent(50, 30, 50, 80) elif direct.lower() == 'left': self.swipe_by_percent(80, 50, 30, 50) else: self.swipe_by_percent(30, 50, 90, 50) if time.time() > maxtime: self._info( "the element %s is not viable,and the direct is %s" % (locator, direct)) raise AssertionError( "the element %s is not viable,and the direct is %s" % (locator, direct)) # Private def _is_index(self, index_or_name): if index_or_name.startswith('index='): return True else: return False def _click_element_by_name(self, name): driver = self._current_application() try: element = driver.find_element_by_name(name) except Exception as e: raise e try: element.click() except Exception as e: raise 'Cannot click the element with name "%s"' % name def _find_elements_by_class_name(self, class_name): driver = self._current_application() elements = driver.find_elements_by_class_name(class_name) return elements def _find_element_by_class_name(self, class_name, index_or_name): elements = self._find_elements_by_class_name(class_name) if self._is_index(index_or_name): try: index = int(index_or_name.split('=')[-1]) element = elements[index] except (IndexError, TypeError): raise 'Cannot find the element with index "%s"' % index_or_name else: found = False for element in elements: self._info("'%s'." % element.text) if element.text == index_or_name: found = True break if not found: raise 'Cannot find the element with name "%s"' % index_or_name return element def _get_class(self, platform_class_dict): return platform_class_dict.get(self._get_platform()) def _is_support_platform(self, platform_class_dict): return platform_class_dict.has_key(self._get_platform()) def _click_element_by_class_name(self, class_name, index_or_name): element = self._find_element_by_class_name(class_name, index_or_name) self._info("Clicking element '%s'." % element.text) try: element.click() except Exception as e: raise 'Cannot click the %s element "%s"' % (class_name, index_or_name) def _element_clear_text_by_locator(self, locator): try: element = self._element_find(locator, True, True) element.clear() except Exception as e: raise e def _element_input_text_by_locator(self, locator, text): try: element = self._element_find(locator, True, True) element.send_keys(text) except Exception as e: raise e def _element_input_text_by_class_name(self, class_name, index_or_name, text): try: element = self._find_element_by_class_name(class_name, index_or_name) except Exception as e: raise e self._info("input text in element as '%s'." % element.text) try: element.send_keys(text) except Exception as e: raise 'Cannot input text "%s" for the %s element "%s"' % ( text, class_name, index_or_name) def _element_input_value_by_locator(self, locator, text): try: element = self._element_find(locator, True, True) element.set_value(text) except Exception as e: raise e def _element_find(self, locator, first_only, required, tag=None): application = self._current_application() elements = None if isstr(locator): _locator = locator elements = self._element_finder.find(application, _locator, tag) if required and len(elements) == 0: raise ValueError("Element locator '" + locator + "' did not match any elements.") if first_only: if len(elements) == 0: return None return elements[0] elif isinstance(locator, WebElement): elements = [locator] if first_only: return locator # do some other stuff here like deal with list of webelements # ... or raise locator/element specific error if required return elements def _element_find_by_text(self, text, exact_match=False): if self._get_platform() == 'ios': element = self._element_find(text, True, False) if element: return element else: if exact_match: _xpath = u'//*[@value="{}" or @label="{}"]'.format( text, text) else: _xpath = u'//*[contains(@label,"{}") or contains(@value, "{}")]'.format( text, text) return self._element_find(_xpath, True, True) elif self._get_platform() == 'android': if exact_match: _xpath = u'//*[@{}="{}"]'.format('text', text) else: _xpath = u'//*[contains(@{},"{}")]'.format('text', text) return self._element_find(_xpath, True, True) def _get_text(self, locator): element = self._element_find(locator, True, True) if element is not None: return element.text return None def _is_text_present(self, text): text_norm = normalize('NFD', text) source_norm = normalize('NFD', self.get_source()) return text_norm in source_norm def _is_element_present(self, locator): application = self._current_application() elements = self._element_finder.find(application, locator, None) return len(elements) > 0 def _is_visible(self, locator): element = self._element_find(locator, True, False) if element is not None: return element.is_displayed() return None
class TestRunnerAgent: """Pass all listener events to a remote listener If called with one argument, that argument is a port, localhost is used as host, 30 seconds is a connection timeout If called with two, the first is a host, the second is a port, 30 seconds is a connection timeout If called with three, the first is a host, the second is a port, the third is a connection timeout """ ROBOT_LISTENER_API_VERSION = 2 CONNECTION_SLEEP_BETWEEN_TRIALS = 2 RED_AGENT_PROTOCOL_VERSION = 2 MAX_VARIABLE_VALUE_TEXT_LENGTH = 2048 def __init__(self, *args): if len(args) == 1: host, port, connection_timeout = 'localhost', int(args[0]), 30 elif len(args) == 2: host, port, connection_timeout = args[0], int(args[1]), 30 else: host, port, connection_timeout = args[0], int(args[1]), int( args[2]) self._last_pause_check = time.time() self._is_connected, self.sock, self.decoder_encoder = self._connect( host, port, connection_timeout) if self._is_connected: self._handshake() self._built_in = BuiltIn() else: self._mode = None def _handshake(self): self._send_to_server(AgentEventMessage.AGENT_INITIALIZING) self._mode, wait_for_signal = self._receive_operating_mode() self._send_version() _, response = self._wait_for_reponse( RedResponseMessage.PROTOCOL_VERSION) is_correct = response[ RedResponseMessage.PROTOCOL_VERSION]['is_correct'] error = response[RedResponseMessage.PROTOCOL_VERSION]['error'] if is_correct and wait_for_signal: self._send_to_server(AgentEventMessage.READY_TO_START) self._wait_for_reponse(RedResponseMessage.DO_START) elif not is_correct: self._close_connection() self._print_error_message( error + '\nClosing connection. Please use agent script as exported from RED instance you\'re using' ) def _receive_operating_mode(self): _, response = self._wait_for_reponse(RedResponseMessage.OPERATING_MODE) operating_mode = response[RedResponseMessage.OPERATING_MODE] return operating_mode['mode'].lower( ), operating_mode['wait_for_start_allowance'] def _send_version(self): robot_version = 'Robot Framework ' + version.get_full_version() info = { 'cmd_line': ' '.join(sys.argv), 'python': sys.version, 'robot': robot_version, 'protocol': self.RED_AGENT_PROTOCOL_VERSION, 'pid': os.getpid() } self._send_to_server(AgentEventMessage.VERSION, info) def start_suite(self, name, attrs): attrs_copy = copy.copy(attrs) del attrs_copy['doc'] attrs_copy['is_dir'] = os.path.isdir(attrs['source']) self._send_to_server(AgentEventMessage.START_SUITE, name, attrs_copy) def end_suite(self, name, attrs): attrs_copy = copy.copy(attrs) del attrs_copy['doc'] attrs_copy['is_dir'] = os.path.isdir(attrs['source']) self._send_to_server(AgentEventMessage.END_SUITE, name, attrs_copy) def start_test(self, name, attrs): attrs_copy = copy.copy(attrs) del attrs_copy['doc'] self._send_to_server(AgentEventMessage.START_TEST, name, attrs_copy) def end_test(self, name, attrs): attrs_copy = copy.copy(attrs) del attrs_copy['doc'] self._send_to_server(AgentEventMessage.END_TEST, name, attrs_copy) def start_keyword(self, name, attrs): if not self._is_connected: return # we're cutting args from original attrs dictionary, because it may contain # objects which are not json-serializable and we don't need them anyway attrs_copy = copy.copy(attrs) del attrs_copy['args'] del attrs_copy['doc'] del attrs_copy['assign'] # this is done in order to reuse json encoded objects as they are sent twice in DEBUG mode json_obj = self._encode_to_json((name, attrs_copy)) if self._mode == AgentMode.DEBUG: self._send_to_server_json(AgentEventMessage.PRE_START_KEYWORD, json_obj) if self._should_pause(PausingPoint.PRE_START_KEYWORD): self._wait_for_resume() self._send_to_server_json(AgentEventMessage.START_KEYWORD, json_obj) if self._should_ask_for_pause_on_start(): if self._should_pause(PausingPoint.START_KEYWORD): self._wait_for_resume() def _should_ask_for_pause_on_start(self): if not self._is_connected: return False elif self._mode == AgentMode.RUN: # in run mode we will check for pause only from time to time (in at least 2 sec intervals) current_time = time.time() if current_time - self._last_pause_check > 2: self._last_pause_check = current_time return True else: return False else: return True def end_keyword(self, name, attrs): if not self._is_connected: return attrs_copy = copy.copy(attrs) del attrs_copy['args'] del attrs_copy['doc'] del attrs_copy['assign'] json_obj = self._encode_to_json((name, attrs_copy)) if self._mode == AgentMode.DEBUG: self._send_to_server_json(AgentEventMessage.PRE_END_KEYWORD, json_obj) if self._should_pause(PausingPoint.PRE_END_KEYWORD): self._wait_for_resume() self._send_to_server_json(AgentEventMessage.END_KEYWORD, json_obj) if self._should_ask_for_pause_on_end(): if self._should_pause(PausingPoint.END_KEYWORD): self._wait_for_resume() def _should_ask_for_pause_on_end(self): return self._is_connected and self._mode == AgentMode.DEBUG def _should_pause(self, pausing_point): self._send_to_server(AgentEventMessage.SHOULD_CONTINUE, {'pausing_point': pausing_point}) possible_responses = [ RedResponseMessage.CONTINUE, RedResponseMessage.PAUSE, RedResponseMessage.TERMINATE, RedResponseMessage.INTERRUPT, RedResponseMessage.DISCONNECT ] if self._mode == AgentMode.DEBUG and pausing_point in [ PausingPoint.PRE_START_KEYWORD, PausingPoint.PRE_END_KEYWORD ]: possible_responses.append(RedResponseMessage.EVALUATE_CONDITION) response_name, response = self._wait_for_reponse(*possible_responses) while True: if response_name == RedResponseMessage.TERMINATE: sys.exit() elif response_name == RedResponseMessage.INTERRUPT: self._interrupt() return False elif response_name == RedResponseMessage.DISCONNECT: self._close_connection() return False elif response_name == RedResponseMessage.CONTINUE: return False elif response_name == RedResponseMessage.PAUSE: return True elif response_name == RedResponseMessage.EVALUATE_CONDITION: return self._evaluate_condition(response) def _interrupt(self): import signal from robot.running import signalhandler signalhandler.STOP_SIGNAL_MONITOR(signal.SIGINT, None) def _evaluate_condition(self, condition): robot_version_str = robot.version.get_version(True) robot_version = tuple( [int(num) for num in re.split('\\.', robot_version_str)]) evaluator = self._evaluate_condition_old_style if robot_version < ( 3, 0, 3) else self._evaluate_condition_new_style elements = condition[RedResponseMessage.EVALUATE_CONDITION] keywordName, argList = elements[0], elements[1:] return evaluator(keywordName, argList) def _evaluate_condition_old_style(self, keywordName, argList): try: result = self._built_in.run_keyword_and_return_status( keywordName, *argList) self._send_to_server(AgentEventMessage.CONDITION_RESULT, {'result': result}) return result except Exception as e: msg = 'Error occurred when evaluating breakpoint condition. ' + str( e) self._send_to_server(AgentEventMessage.CONDITION_RESULT, {'error': msg}) return True def _evaluate_condition_new_style(self, keywordName, argList): try: self._built_in.run_keyword(keywordName, *argList) self._send_to_server(AgentEventMessage.CONDITION_RESULT, {'result': True}) return True except (HandlerExecutionFailed, UserKeywordExecutionFailed) as e: self._send_to_server(AgentEventMessage.CONDITION_RESULT, {'result': False}) return False except Exception as e: msg = 'Error occurred when evaluating breakpoint condition. ' + str( e) self._send_to_server(AgentEventMessage.CONDITION_RESULT, {'error': msg}) return True def _wait_for_resume(self): if not self._is_connected: return possible_responses = [ RedResponseMessage.RESUME, RedResponseMessage.TERMINATE, RedResponseMessage.INTERRUPT, RedResponseMessage.DISCONNECT ] if self._mode == AgentMode.DEBUG: possible_responses.append(RedResponseMessage.CHANGE_VARIABLE) self._send_variables() while True: self._send_to_server(AgentEventMessage.PAUSED) response_name, response = self._wait_for_reponse( *possible_responses) if response_name == RedResponseMessage.RESUME: self._send_to_server(AgentEventMessage.RESUMED) return elif response_name == RedResponseMessage.TERMINATE: sys.exit() elif response_name == RedResponseMessage.INTERRUPT: self._send_to_server(AgentEventMessage.RESUMED) self._interrupt() return elif response_name == RedResponseMessage.DISCONNECT: self._close_connection() return elif response_name == RedResponseMessage.CHANGE_VARIABLE: try: self._change_variable_value(response) self._send_variables() except ValueError as e: self._print_error_message(str(e)) self._send_variables(str(e)) def _change_variable_value(self, response): try: arguments = response[RedResponseMessage.CHANGE_VARIABLE] var_name = arguments['name'] scope = arguments['scope'] if scope not in ['local', 'test_case', 'test_suite', 'global']: raise ValueError('Unable to change value of variable ' + var_name + ' inside unrecognized scope ' + str(scope)) new_values = arguments['values'] level = arguments[ 'level'] + 1 # adding one because globals are not taken into account if 'path' in arguments: self._change_variable_inner_value(var_name, level, arguments['path'], new_values) else: self._change_variable_on_top_level(var_name, scope, level, new_values) except Exception as e: raise ValueError('Unable to change value of variable ' + var_name + '. ' + str(e)) def _change_variable_on_top_level(self, var_name, scope, level, new_values): # WARNING : this method uses protected RF methods/fields so it is sensitive for RF changes; # currently works fine for RF 2.9 - 3.0 if scope == 'local': name = self._built_in._get_var_name(var_name) value = self._built_in._get_var_value(name, new_values) self._built_in._variables._scopes[level][name] = value self._built_in._log_set_variable(name, value) elif scope == 'test_case': self._built_in.set_test_variable(var_name, *new_values) elif scope == 'test_suite': if level >= len(self._built_in._variables._scopes) - len( list(self._built_in._variables._scopes_until_suite)): # variable in lowest suite, so we'll use keyword self._built_in.set_suite_variable(var_name, *new_values) else: # variable in higher order suite name = self._built_in._get_var_name(var_name) value = self._built_in._get_var_value(name, new_values) self._built_in._variables._scopes[level][name] = value self._built_in._variables._variables_set._scopes[ level - 1][name] = value self._built_in._log_set_variable(name, value) else: self._built_in.set_global_variable(var_name, *new_values) def _change_variable_inner_value(self, name, level, path, new_values): # WARNING : this method uses protected RF methods/fields so it is sensitive for RF changes; # currently works fine for RF 2.9 - 3.0 types = {'scalar': '$', 'list': '@', 'dict': '&'} value = self._built_in._get_var_value( types[path[-1][0]] + '{temp_name}', new_values) old_value = self._built_in._variables._scopes[level].as_dict()[name] self._change_inner_value(old_value, path[:-1], value) def _change_inner_value(self, object, path, value): val_kind, addr = path[0] if val_kind == 'list' and isinstance( object, (list, tuple)) or val_kind == 'dict' and isinstance( object, Mapping): if len(path) == 1: object[addr] = value else: self._change_inner_value(object[addr], path[1:], value) else: raise RuntimeError('Requested to change value in ' + val_kind + ' object type, but ' + type(object).__name__ + ' found') def _send_variables(self, error=None): vars = self._collect_variables() if error: self._send_to_server(AgentEventMessage.VARIABLES, { 'var_scopes': vars, 'error': error }) else: self._send_to_server(AgentEventMessage.VARIABLES, {'var_scopes': vars}) def _collect_variables(self): # WARNING : this method uses protected RF methods/fields so it is sensitive for RF changes; # currently works fine for RF 2.9 - 3.0 variables = self._built_in._variables frames = variables._scopes all_frames = [] i = 0 last_suite_index = frames.index(variables._suite) test_index = frames.index(variables._test) if variables._test else -1 for current_frame in frames: current_frame_values = {} frame_vars = OrderedDict() for variable in current_frame.store: value = current_frame.store[variable] var, _ = current_frame.store._decorate(variable, value) if i == 0: identified_scope = 'global' elif var in previous_frame_values and value == previous_frame_values[ var][1]: identified_scope = previous_frame_values[var][0] elif i <= last_suite_index: identified_scope = 'suite' elif i == test_index: identified_scope = 'test' if '$' + var[ 1:] in variables._variables_set._test else 'local' else: identified_scope = 'local' if inspect.ismodule(value) or inspect.isfunction( value) or inspect.isclass(value): type_name = type(value).__name__ frame_vars[var] = (type_name, type_name + '@' + str(id(value)), identified_scope) else: try: labeled = _label_with_types(value) fixed = _fix_unicode( self.MAX_VARIABLE_VALUE_TEXT_LENGTH, labeled) if isinstance(value, (list, tuple, Mapping)): frame_vars[var] = (fixed[0], fixed[1], identified_scope) else: frame_vars[var] = (fixed[0], str(fixed[1]), identified_scope) except: frame_vars[var] = (type(value).__name__, '<error retrieving value>', identified_scope) current_frame_values[var] = (identified_scope, value) all_frames.append(frame_vars) previous_frame_values = current_frame_values i += 1 all_frames.reverse() return all_frames def resource_import(self, name, attributes): self._send_to_server(AgentEventMessage.RESOURCE_IMPORT, name, attributes) def library_import(self, name, attributes): # equals org.python.core.ClasspathPyImporter.PYCLASSPATH_PREFIX if 'Jython' in platform.python_implementation(): import org.python.core.imp as jimp if attributes['source']: if '__pyclasspath__' in attributes['source']: res = attributes['source'].split( '__pyclasspath__')[1].replace(os.sep, '') attributes['source'] = str( jimp.getSyspathJavaLoader().getResources( res).nextElement()) else: try: source_uri = jimp.getSyspathJavaLoader().getResources( name + '.class').nextElement() attributes['source'] = str(source_uri) except: pass source_uri_txt = attributes['source'] if source_uri_txt and 'file:/' in source_uri_txt: from java.io import File as File from java.net import URL as URL filePath = re.split('.*(?=file[:])', source_uri_txt) if len(filePath) > 1: path = re.split('[!][/]', filePath[1])[0] f = File(URL(path).getFile()) source_uri_txt = f.getAbsolutePath() attributes['source'] = source_uri_txt self._send_to_server(AgentEventMessage.LIBRARY_IMPORT, name, attributes) def message(self, message): if message['level'] in ('ERROR', 'FAIL', 'NONE'): self._send_to_server(AgentEventMessage.MESSAGE, message) def log_message(self, message): if _is_logged(message['level']): message['message'] = _truncate(self.MAX_VARIABLE_VALUE_TEXT_LENGTH, message['message']) self._send_to_server(AgentEventMessage.LOG_MESSAGE, message) def log_file(self, path): self._send_to_server(AgentEventMessage.LOG_FILE, path) def output_file(self, path): self._send_to_server(AgentEventMessage.OUTPUT_FILE, path) def report_file(self, path): self._send_to_server(AgentEventMessage.REPORT_FILE, path) def summary_file(self, path): pass def debug_file(self, path): pass def close(self): self._send_to_server(AgentEventMessage.CLOSE) self._close_connection() def _print_error_message(self, message): sys.stderr.write('[ ERROR ] ' + message + '\n') sys.stderr.flush() def _connect(self, host, port, connection_timeout): '''Establish a connection for sending data''' trials = 1 start = time.time() while int(time.time() - start) < connection_timeout: sock = None try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((host, port)) return True, sock, MessagesDecoderEncoder(sock) except socket.error as e: print('TestRunnerAgent: connection trial #%s failed' % trials) print('\tUnable to open socket to "%s:%s"' % (host, port)) print('\terror: %s' % str(e)) time.sleep(self.CONNECTION_SLEEP_BETWEEN_TRIALS) trials += 1 return False, None, None def _encode_to_json(self, obj): try: if self.decoder_encoder: return self.decoder_encoder._encode(obj) except Exception: traceback.print_exc(file=sys.stdout) sys.stdout.flush() raise def _send_to_server(self, name, *args): try: if self.decoder_encoder: packet = {name: args} self.decoder_encoder.dump(packet) except Exception: traceback.print_exc(file=sys.stdout) sys.stdout.flush() raise def _send_to_server_json(self, name, json_encoded_obj): try: if self.decoder_encoder: self.decoder_encoder._write('{"%s": %s}' % (name, json_encoded_obj)) except Exception: traceback.print_exc(file=sys.stdout) sys.stdout.flush() raise def _wait_for_reponse(self, *expected_responses): response = self._receive_from_server() response_key = next(iter(response)) while not response_key in expected_responses: response = self._receive_from_server() return response_key, response def _receive_from_server(self): try: if self.decoder_encoder: return self.decoder_encoder.load() except Exception: traceback.print_exc(file=sys.stdout) sys.stdout.flush() raise def _close_connection(self): if self._is_connected: self._mode = None self._is_connected = False self.decoder_encoder.close() self.decoder_encoder = None self.sock.close() self.sock = None
def __init__(self): self.logger = robot.api.logger self.builtin = BuiltIn() self.account = None
class EmailUtil(object): def __init__(self): self.logger = robot.api.logger self.builtin = BuiltIn() self.account = None def send_email(self, sender, subject='', *recipients): msg = MIMEMultipart() msg['Subject'] = subject msg['From'] = sender msg['To'] = ", ".join(recipients) server = smtplib.SMTP('mta-hub.int.carlsonwagonlit.com', 25) server.sendmail(sender, recipients, msg.as_string()) server.quit() def send_email_with_message_text(self, sender, subject='', message_text='test', cc=None, *recipients): # def send_email_with_message_text(self, sender, subject='', message_text='test', *recipients): message = "From: %s\r\n" % sender \ + "To: %s\r\n" % ",".join(recipients) \ + "Cc: %s\r\n" % ",".join([cc]) \ + "Subject: %s\r\n" % subject \ + "\r\n" + message_text if cc: recipients = [recipients] + [cc] else: recipients = [recipients] server = smtplib.SMTP('mta-hub.int.carlsonwagonlit.com', 25) # server.set_debuglevel(1) server.sendmail(sender, recipients, message) server.quit() def send_email_with_attachment(self, sender, attachment_file, subject='', *recipients): msg = MIMEMultipart() msg['From'] = sender msg['To'] = ", ".join(recipients) msg['Subject'] = subject part = MIMEBase('application', "plain") part.set_payload(open(attachment_file, "rb").read()) encoders.encode_base64(part) filename = os.path.basename(attachment_file) part.add_header('Content-Disposition', 'attachment; filename="%s"' % filename) msg.attach(part) server = smtplib.SMTP('mta-hub.int.carlsonwagonlit.com', 25) server.sendmail(sender, recipients, msg.as_string()) server.quit() def connect_to_exchange(self, server, email, username, password): try: cred = Credentials(username=username, password=password) config = Configuration(server=server, credentials=cred) self.account = Account(primary_smtp_address=email, autodiscover=False, config=config, access_type=DELEGATE) return self.account except UnauthorizedError: self.builtin.fail('Wrong username or password for ' + server ) def get_recent_emails(self, folder_name, count=10): try: folder = self.account.root / 'Top of Information Store' / folder_name return folder.all().order_by('-datetime_received')[:count] except ErrorFolderNotFound: self.builtin.fail('No subfolder with name ' + folder_name) def get_email_text_body_from(self, sender, count=1): """ Prereq: Use "Connect To Exchange" kw before calling this Returns values in list if count is more than 1 """ mail = self.account.inbox.filter(sender=sender).order_by('-datetime_received')[:count] text_body = [v.text_body for v in mail] return ''.join(text_body) if count < 2 else text_body def get_email_subject_from(self, sender, count=1): """ Prereq: Use "Connect To Exchange" kw before calling this Returns values in list if count is more than 1 """ mail = self.account.inbox.filter(sender=sender).order_by('-datetime_received')[:count] subject = [v.subject for v in mail] return ''.join(subject) if count < 2 else subject def get_recent_caseid(self, sender): """ Prereq: Use "Connect To Exchange" kw before calling this """ email_subject = self.get_email_subject_from(sender) try: case_id = re.search(r'.*Request:\s(\w*-\w*)\s.*', email_subject).group(1) except Exception: case_id = '' self.logger.info(case_id) return case_id
class RobotEyes(object): output_dir = '' images_base_folder = '' test_name = '' baseline_dir = '' browser = None ROBOT_LISTENER_API_VERSION = 2 ROBOT_LIBRARY_SCOPE = 'GLOBAL' # Keeping this arg to avoid exceptions for those who have added tolerance in the previous versions. def __init__(self, tolerance=0): self.ROBOT_LIBRARY_LISTENER = self def open_eyes(self, lib='SeleniumLibrary', tolerance=0): self.tolerance = float(tolerance) self.tolerance = self.tolerance / 100 if self.tolerance >= 1 else self.tolerance self.stats = {} self.fail = False self.baseline_dir = self._get_baseline_dir() self.output_dir = self._output_dir() self.images_base_folder = os.path.join(self.output_dir, IMAGES_FOLDER) self.browser = SeleniumHooks(lib) self.test_name = BuiltIn().replace_variables('${TEST NAME}') test_name_folder = self.test_name.replace(' ', '_') # delete if directory already exist. Fresh test self._delete_folder_if_exists(test_name_folder) # recreate deleted folder self._create_empty_folder(test_name_folder) self.count = 1 # Captures full screen def capture_full_screen(self, tolerance=None, blur=[], radius=50, name=None, redact=[]): tolerance = float(tolerance) if tolerance else self.tolerance tolerance = tolerance / 100 if tolerance >= 1 else tolerance name = self._get_name() if name is None else name name += '.png' path = os.path.join(self.path, name) self.browser.capture_full_screen(path, blur, radius, redact) if self.browser.is_mobile(): self._fix_base_image_size(path, name) else: self._resize(path) self.stats[name] = tolerance self.count += 1 # Captures a specific region in a mobile screen def capture_mobile_element(self, selector, tolerance=None, blur=[], radius=50, name=None, redact=[]): tolerance = float(tolerance) if tolerance else self.tolerance name = self._get_name() if name is None else name name += '.png' path = os.path.join(self.path, name) self.browser.capture_mobile_element(selector, path, blur, radius, redact) self.stats[name] = tolerance self.count += 1 # Captures a specific region in a webpage def capture_element(self, selector, tolerance=None, blur=[], radius=50, name=None, redact=[]): tolerance = float(tolerance) if tolerance else self.tolerance tolerance = tolerance / 100 if tolerance >= 1 else tolerance name = self._get_name() if name is None else name name += '.png' path = os.path.join(self.path, name) time.sleep(1) self.browser.capture_element(path, selector, blur, radius, redact) self.stats[name] = tolerance self.count += 1 def scroll_to_element(self, selector): self.browser.scroll_to_element(selector) def compare_two_images(self, first, second, output, tolerance=None): tolerance = float(tolerance) if tolerance else self.tolerance if not first or not second: raise Exception('Please provide first and second image paths') first_path = os.path.join(self.path, first) first_path += '.png' if not first_path.endswith('.png') else '' second_path = os.path.join(self.path, second) + '.png' second_path += '.png' if not second_path.endswith('.png') else '' output += '.png' if not output.endswith('.png') else '' test_name = self.test_name.replace(' ', '_') diff_path = os.path.join(self.images_base_folder, DIFF_IMAGE_BASE_FOLDER, test_name) if os.path.exists(first_path) and os.path.exists(second_path): if not os.path.exists(diff_path): os.makedirs(diff_path) diff_path = os.path.join(diff_path, output) difference = Imagemagick(first_path, second_path, diff_path).compare_images() color, result = self._get_result(difference, tolerance) self.stats[output] = tolerance text = '%s %s' % (result, color) outfile = open(self.path + os.sep + output + '.txt', 'w') outfile.write(text) outfile.close() base_path = os.path.join(self.baseline_dir, test_name, output) actual_path = os.path.join(self.path, output) shutil.copy(first_path, base_path) shutil.copy(second_path, actual_path) else: raise Exception('Image %s or %s doesnt exist' % (first, second)) def compare_images(self): test_name = self.test_name.replace(' ', '_') baseline_path = os.path.join(self.baseline_dir, test_name) actual_path = os.path.join(self.images_base_folder, ACTUAL_IMAGE_BASE_FOLDER, test_name) diff_path = os.path.join(self.images_base_folder, DIFF_IMAGE_BASE_FOLDER, test_name) if not os.path.exists(diff_path): os.makedirs(diff_path) # compare actual and baseline images and save the diff image for filename in os.listdir(actual_path): if filename.endswith('.png'): b_path = os.path.join(baseline_path, filename) a_path = os.path.join(actual_path, filename) d_path = os.path.join(diff_path, filename) if os.path.exists(b_path): difference = Imagemagick(b_path, a_path, d_path).compare_images() try: threshold = float(self.stats[filename]) except ValueError: raise Exception('Invalid tolerance: %s' % self.stats[filename]) color, result = self._get_result(difference, threshold) text = '%s %s' % (result, color) else: shutil.copy(a_path, b_path) text = '%s %s' % ('None', 'green') output = open(actual_path + os.path.sep + filename + '.txt', 'w') output.write(text) output.close() BuiltIn().run_keyword( 'Fail', 'Image dissimilarity exceeds tolerance') if self.fail else '' def _delete_folder_if_exists(self, test_name_folder): actual_image_test_folder = os.path.join(self.images_base_folder, ACTUAL_IMAGE_BASE_FOLDER, test_name_folder) diff_image_test_folder = os.path.join(self.images_base_folder, DIFF_IMAGE_BASE_FOLDER, test_name_folder) if os.path.exists(actual_image_test_folder): shutil.rmtree(actual_image_test_folder) if os.path.exists(diff_image_test_folder): shutil.rmtree(diff_image_test_folder) def _create_empty_folder(self, test_name_folder): self.path = os.path.join(self.baseline_dir, test_name_folder) if not os.path.exists(self.path): os.makedirs(self.path) self.path = os.path.join(self.images_base_folder, ACTUAL_IMAGE_BASE_FOLDER, test_name_folder) if not os.path.exists(self.path): os.makedirs(self.path) def _resize(self, *args): for arg in args: img = Image.open(arg) img = img.resize((1024, 700), Image.ANTIALIAS) img.save(arg) def _fix_base_image_size(self, path, image_name): test_name = self.test_name.replace(' ', '_') base_image = os.path.join(self.baseline_dir, test_name, image_name) if os.path.exists(base_image): im = Image.open(path) width, height = im.size im.close() im = Image.open(base_image) b_width, b_height = im.size if width != b_width or height != b_height: im = im.resize((width, height), Image.ANTIALIAS) im.save(base_image) def _delete_report_if_old(self, path): t1 = datetime.fromtimestamp(os.path.getmtime(path)) t2 = datetime.now() diff = (t2 - t1).seconds os.remove(path) if diff > REPORT_EXPIRATION_THRESHOLD else '' def _output_dir(self): output_dir = BuiltIn().replace_variables('${OUTPUT DIR}') if 'pabot_results' in output_dir: index = output_dir.find(os.path.sep + 'pabot_results') return output_dir[:index] return output_dir def _get_result(self, difference, threshold): difference, threshold = int(difference * 100), int(threshold * 100) if difference > threshold: color = 'red' result = '%s<%s' % (threshold, difference) self.fail = True elif difference == threshold: color = 'green' result = '%s==%s' % (threshold, difference) else: color = 'green' result = '%s>%s' % (threshold, difference) return color, result def _get_baseline_dir(self): baseline_dir = BuiltIn().get_variable_value('${images_dir}') if not baseline_dir: BuiltIn().run_keyword( 'Fail', 'Please provide image baseline directory. Ex: -v images_dir:base' ) os.makedirs(baseline_dir) if not os.path.exists(baseline_dir) else '' return baseline_dir def _get_name(self): return 'img%s' % str(self.count) def _close(self): images_base_folder = self.images_base_folder.replace(os.getcwd(), '')[1:] if self.baseline_dir and images_base_folder: thread = Thread(target=generate_report, args=( self.baseline_dir, os.path.join(self.output_dir, 'output.xml'), images_base_folder, )) thread.start()
def _do_eval(self, debugger_impl): frame_id = self.frame_id stack_info = debugger_impl._get_stack_info_from_frame_id(frame_id) if stack_info is None: raise InvalidFrameIdError( "Unable to find frame id for evaluation: %s" % (frame_id, )) info = stack_info._frame_id_to_frame_info.get(frame_id) if info is None: raise InvalidFrameIdError( "Unable to find frame info for evaluation: %s" % (frame_id, )) if not isinstance(info, _KeywordFrameInfo): raise InvalidFrameTypeError( "Can only evaluate at a Keyword context (current context: %s)" % (info.get_type_name(), )) log.info("Doing evaluation in the Keyword context: %s", info.keyword) from robotframework_ls.impl.text_utilities import is_variable_text from robot.libraries.BuiltIn import BuiltIn # type: ignore from robot.api import get_model # type: ignore from robotframework_ls.impl import ast_utils # We can't really use # BuiltIn().evaluate(expression, modules, namespace) # because we can't set the variable_store used with it # (it always uses the latest). variable_store = info.variables.store if is_variable_text(self.expression): try: value = variable_store[self.expression[2:-1]] except Exception: pass else: return EvaluationResult(value) # Do we want this? # from robot.variables.evaluation import evaluate_expression # try: # result = evaluate_expression(self.expression, variable_store) # except Exception: # log.exception() # else: # return EvaluationResult(result) # Try to check if it's a KeywordCall. s = """ *** Test Cases *** Evaluation %s """ % (self.expression, ) model = get_model(s) usage_info = list(ast_utils.iter_keyword_usage_tokens(model)) if len(usage_info) == 1: _stack, node, _token, name = next(iter(usage_info)) dap_frames = stack_info.dap_frames if dap_frames: top_frame_id = dap_frames[0].id if top_frame_id != frame_id: if get_log_level() >= 2: log.debug( "Unable to evaluate.\nFrame id for evaluation: %r\nTop frame id: %r.\nDAP frames:\n%s", frame_id, top_frame_id, "\n".join(x.to_json() for x in dap_frames), ) raise UnableToEvaluateError( "Keyword calls may only be evaluated at the topmost frame." ) return EvaluationResult(BuiltIn().run_keyword( name, *node.args)) raise UnableToEvaluateError("Unable to evaluate: %s" % (self.expression, ))
def __init__(self,commonobj,objSuite): """ """ self.robot_env = BuiltIn() self.commonobj = commonobj self.objSuite = objSuite
def get_variable(name, default=None): return BuiltIn().get_variable_value("${" + name + "}", default=default)
def call_keyword(keyword): return BuiltIn().run_keyword(keyword)
def get_webdriver_instance(): se2lib = BuiltIn().get_library_instance('Selenium2Library') CurWebDriver = se2lib._current_browser() return CurWebDriver
def wait_until_all_nodes_are_ready(self, *args, **kwargs): """ Wait Until Node Ready [Args] (dict) conn: Connection dictionary obtained after logging in (str) Name: Name of the Node [Returns] (dict) Wait Time (dict) Error response: If Exception occured """ self._load_kwargs(kwargs) banner("PCC.Wait Until All Nodes are Ready") conn = BuiltIn().get_variable_value("${PCC_CONN}") all_node_list = pcc.get_nodes(conn)['Result']['Data'] node_ready_status = [] try: for node_name in all_node_list: ready = False time_waited = 0 PCC_TIMEOUT = 60 * 10 #10 minutes timeout = time.time() + PCC_TIMEOUT while not ready: ready = False node_list = pcc.get_nodes(conn)['Result']['Data'] for node in node_list: if str(node['Name']) == str(node_name['Name']): if node['provisionStatus'] == 'Ready': trace("Node:{} is ready".format( node_name['Name'])) node_ready_status.append("OK") ready = True break if "fail" in node['provisionStatus']: node_ready_status.append("Failed:{}".format( node['Name'])) trace( "Wait until node ready status - Failed on node {}. Node Status is {}" .format(node_name['Name'], node['provisionStatus'])) print( "Wait until node ready status - Failed on node {}. Node Status is {}" .format(node_name['Name'], node['provisionStatus'])) ready = True break if time.time() > timeout: print("Error: Timeout for node {}".format( node_name['Name'])) node_ready_status.append("Timeout: {}".format( node_name['Name'])) ready = True break if not ready: trace("Node:{} is not yet ready".format( node_name['Name'])) time.sleep(5) time_waited += 5 node_ready_result = len(node_ready_status) > 0 and all( elem == "OK" for elem in node_ready_status) if node_ready_result: return "OK" else: return "Wait Until Node ready status is: {}".format( node_ready_status) except Exception as e: return "Exception encountered: {}".format(e)
def __init__(self): self._element_finder = ElementFinder() self._bi = BuiltIn()
def verify_node_back_end(self, *args, **kwargs): banner("PCC.Node Verify Back End") self._load_kwargs(kwargs) print("Kwargs:{}".format(kwargs)) pcc_agent_cmd = "sudo systemctl status pccagent" sys_cllector_cmd = "sudo systemctl status systemCollector" frr_cmd = "sudo service frr status|head -10" failed_host = {} successful_host = {} if self.host_ips: for host_ip in eval(str(self.host_ips)): successful_host[host_ip] = "OK" for i in range(1, 37): logger.console( "Verifying services for host {} .....".format(host_ip)) pcc_agent_output = cli_run(host_ip, self.user, self.password, pcc_agent_cmd) sys_collector_output = cli_run(host_ip, self.user, self.password, sys_cllector_cmd) logger.console( "Pcc Agent Output: {}".format(pcc_agent_output)) logger.console("System Collector Output: {}".format( sys_collector_output)) #frr_output=cli_run(host_ip,self.user,self.password,frr_cmd) #logger.console("Frr Service Output: {}".format(frr_output)) #if re.search("running",str(pcc_agent_output)) and re.search("running",str(sys_collector_output) and re.search("running",str(frr_output))): if re.search("running", str(pcc_agent_output)) and re.search( "running", str(sys_collector_output)): print( "===== pccagent and systemCollector are running for {} =======" .format(host_ip)) failed_host[host_ip] = "OK" break if re.search("inactive", str(pcc_agent_output)) or re.search( "inactive", str(sys_collector_output)): time.sleep(10) failed_host[host_ip] = "inactive" print( "===== Services inactive found for {}. Retrying:{}...=======" .format(host_ip, i)) continue if re.search("service could not be found", str(pcc_agent_output)) or re.search( "service could not be found", str(sys_collector_output)): time.sleep(10) failed_host[host_ip] = "service not found" print( "====== Services not found for {}. Retrying:{}...=======" .format(host_ip, i)) continue else: print( "Host list is empty, please provide the host ip in a list for eg. host_ips=['000.00.0.00']" ) print("Failed host is :{} and successful host is :{}".format( failed_host, successful_host)) if failed_host == successful_host: return "OK" else: BuiltIn().fatal_error( 'Stoping the exectuion, Nodes are not properly added please check !!!' ) return "Error:Node backend status is {}".format(failed_host)
def cleanup_images_present_on_node(self, *args, **kwargs): """ PCC.Cleanup images present on Node from backend [Args] None [Returns] (str) OK: Returns "OK" if all images are cleaned from nodes else: returns "Error" """ banner("PCC.Cleanup images present on Node from backend") self._load_kwargs(kwargs) conn = BuiltIn().get_variable_value("${PCC_CONN}") try: response = self.get_nodes() node_hostips = [] image_deletion_status = [] if get_response_data(response) == []: return "No nodes present on PCC" else: counter = 1 for node in get_response_data(response): node_hostips.append(node['Host']) cmd = "sudo docker images -a|wc -l" cmd1 = "sudo docker rmi -f $(sudo docker images -a -q)" cmd2 = "sudo docker images -a -q|wc -l" print("Cmd1 is: {}".format(cmd1)) print("Cmd2 is: {}".format(cmd2)) for hostip in node_hostips: cmd_response = self._serialize_response( time.time(), cli_run(hostip, self.user, self.password, cmd))['Result']['stdout'] if str(cmd_response).strip() == "1": image_deletion_status.append("OK") else: cmd1_response = self._serialize_response( time.time(), cli_run(hostip, self.user, self.password, cmd1))['Result']['stdout'] if re.search("Deleted:", str(cmd1_response)) or re.search( "Untagged:", str(cmd1_response)): image_deletion_status.append("OK") else: image_deletion_status.append( "Failed at {} for node {}".format( cmd1, hostip)) time.sleep(1) cmd2_response = self._serialize_response( time.time(), cli_run(hostip, self.user, self.password, cmd2))['Result']['stdout'] if str(cmd2_response).strip() == "0": image_deletion_status.append("OK") else: image_deletion_status.append( "Failed at {} for node {}".format( cmd2, hostip)) status = len(image_deletion_status) > 0 and all( elem == "OK" for elem in image_deletion_status) if status: return "OK" return "Images not yet deleted from nodes-> status is: {} and image_deletion_status is {}".format( status, image_deletion_status) except Exception as e: return "Exception encountered: {}".format(e)
def HPA_check(): steps = ['step1_check_initial_replica_count', 'step2_check_scale_out', 'step3_check_scale_in'] BuiltIn().run_keyword("HPA_check.setup") common_utils.keyword_runner(steps)
def execute_ssh_command(cmd_buf, open_connection_args={}, login_args={}, print_out=0, print_err=0, ignore_err=1, fork=0, quiet=None, test_mode=None, time_out=None): r""" Run the given command in an SSH session and return the stdout, stderr and the return code. If there is no open SSH connection, this function will connect and login. Likewise, if the caller has not yet logged in to the connection, this function will do the login. NOTE: There is special handling when open_connection_args['alias'] equals "device_connection". - A write, rather than an execute_command, is done. - Only stdout is returned (no stderr or rc). - print_err, ignore_err and fork are not supported. Description of arguments: cmd_buf The command string to be run in an SSH session. open_connection_args A dictionary of arg names and values which are legal to pass to the SSHLibrary open_connection function as parms/args. At a minimum, this should contain a 'host' entry. login_args A dictionary containing the key/value pairs which are acceptable to the SSHLibrary login function as parms/args. At a minimum, this should contain a 'username' and a 'password' entry. print_out If this is set, this function will print the stdout/stderr generated by the shell command. print_err If show_err is set, this function will print a standardized error report if the shell command returns non-zero. ignore_err Indicates that errors encountered on the sshlib.execute_command are to be ignored. fork Indicates that sshlib.start is to be used rather than sshlib.execute_command. quiet Indicates whether this function should run the pissuing() function which prints an "Issuing: <cmd string>" to stdout. This defaults to the global quiet value. test_mode If test_mode is set, this function will not actually run the command. This defaults to the global test_mode value. time_out The amount of time to allow for the execution of cmd_buf. A value of None means that there is no limit to how long the command may take. """ gp.lprint_executing() # Obtain default values. quiet = int(gp.get_var_value(quiet, 0)) test_mode = int(gp.get_var_value(test_mode, 0)) if not quiet: gp.pissuing(cmd_buf, test_mode) gp.lpissuing(cmd_buf, test_mode) if test_mode: return "", "", 0 global sshlib max_exec_cmd_attempts = 2 # Look for existing SSH connection. # Prepare a search connection dictionary. search_connection_args = open_connection_args.copy() # Remove keys that don't work well for searches. search_connection_args.pop("timeout", None) connection = find_connection(search_connection_args) if connection: gp.lprint_timen("Found the following existing connection:") gp.lprintn(sprint_connection(connection)) if connection.alias == "": index_or_alias = connection.index else: index_or_alias = connection.alias gp.lprint_timen("Switching to existing connection: \"" + str(index_or_alias) + "\".") sshlib.switch_connection(index_or_alias) else: gp.lprint_timen("Connecting to " + open_connection_args['host'] + ".") cix = sshlib.open_connection(**open_connection_args) try: login_ssh(login_args) except Exception: except_type, except_value, except_traceback = sys.exc_info() rc = 1 stderr = str(except_value) stdout = "" max_exec_cmd_attempts = 0 for exec_cmd_attempt_num in range(1, max_exec_cmd_attempts + 1): gp.lprint_var(exec_cmd_attempt_num) try: if fork: sshlib.start_command(cmd_buf) else: if open_connection_args['alias'] == "device_connection": stdout = sshlib.write(cmd_buf) stderr = "" rc = 0 else: stdout, stderr, rc = \ func_timer.run(sshlib.execute_command, cmd_buf, return_stdout=True, return_stderr=True, return_rc=True, time_out=time_out) except Exception: except_type, except_value, except_traceback = sys.exc_info() gp.lprint_var(except_type) gp.lprint_varx("except_value", str(except_value)) # This may be our last time through the retry loop, so setting # return variables. rc = 1 stderr = str(except_value) stdout = "" if except_type is exceptions.AssertionError and\ re.match(r"Connection not open", str(except_value)): try: login_ssh(login_args) # Now we must continue to next loop iteration to retry the # execute_command. continue except Exception: except_type, except_value, except_traceback =\ sys.exc_info() rc = 1 stderr = str(except_value) stdout = "" break if (except_type is paramiko.ssh_exception.SSHException and re.match(r"SSH session not active", str(except_value))) or\ ((except_type is socket.error or except_type is ConnectionResetError) and re.match(r"\[Errno 104\] Connection reset by peer", str(except_value))) or\ (except_type is paramiko.ssh_exception.SSHException and re.match(r"Timeout opening channel\.", str(except_value))): # Close and re-open a connection. # Note: close_connection() doesn't appear to get rid of the # connection. It merely closes it. Since there is a concern # about over-consumption of resources, we use # close_all_connections() which also gets rid of all # connections. gp.lprint_timen("Closing all connections.") sshlib.close_all_connections() gp.lprint_timen("Connecting to " + open_connection_args['host'] + ".") cix = sshlib.open_connection(**open_connection_args) login_ssh(login_args) continue # We do not handle any other RuntimeErrors so we will raise the exception again. sshlib.close_all_connections() gp.lprintn(traceback.format_exc()) raise (except_value) # If we get to this point, the command was executed. break if fork: return if rc != 0 and print_err: gp.print_var(rc, gp.hexa()) if not print_out: gp.print_var(stderr) gp.print_var(stdout) if print_out: gp.printn(stderr + stdout) if not ignore_err: message = gp.sprint_error("The prior SSH" + " command returned a non-zero return" + " code:\n" + gp.sprint_var(rc, gp.hexa()) + stderr + "\n") BuiltIn().should_be_equal(rc, 0, message) if open_connection_args['alias'] == "device_connection": return stdout return stdout, stderr, rc
def _remotelib(self): if self.__remotelib is None: uri = BuiltIn().get_variable_value('${PABOTLIBURI}') logger.debug('PabotLib URI %r' % uri) self.__remotelib = Remote(uri) if uri else None return self.__remotelib
def s2l(self): return BuiltIn().get_library_instance('Selenium2Library')
import json import pytz import time import datetime from logging import warning from SeleniumLibrary.utils import is_noney from robot.libraries.BuiltIn import BuiltIn from SeleniumLibrary.keywords.waiting import WaitingKeywords from selenium.webdriver.remote.webelement import WebElement from typing import Union import utilities_init import os import re from urllib.parse import urlparse sl = BuiltIn().get_library_instance('SeleniumLibrary') element_finder = sl._element_finder waiting = WaitingKeywords(sl) # Should only initialise some parts once e.g. registration # of custom locators onto the framework's ElementFinder if not utilities_init.initialised: def _normalize_parent_locator(parent_locator: object) -> Union[str, WebElement]: if not isinstance(parent_locator, str) and not isinstance(parent_locator, WebElement): return 'css:body' return parent_locator def _find_by_label(parent_locator: object, criteria: str, tag: str, constraints: dict) -> list: parent_locator = _normalize_parent_locator(parent_locator)
class CustomSeleniumLibrary(object): ROBOT_LIBRARY_VERSION = '0.1' def __init__(self): self.get_lib def get_keyword_names(self): return [ name for name in dir(self) if hasattr(getattr(self, name), 'robot_name') ] @property def get_lib(self): try: self.lib = BuiltIn().get_library_instance('SeleniumLibrary') except RobotNotRunningError: self.lib = None @keyword def high_light(self, locator): """ This keyword use to highlight the web element(defined by locator parameter) in the webpage. ``locator`` (WebElement locator) : the locator to identify the element. """ element = self.selenium.find_element(locator) self.lib.driver.execute_script( "arguments[0].style.border='3px solid red'", element) @keyword def upload_image(self, url, file_name, _data): """ This keyword use to upload file to create job. The job ID will be returned. ``url`` (str) : webservice url. ``file_names`` (str): files name. ``data`` (dict): the dictionary contains transactionID, buttonID, buttonContext, sessionID """ _cookie = {"KFS_AUTH_THINCLIENT": _data['sessionID']} file = os.path.join(os.getcwd(), "SmokeTest-WS", "TestResource", "Documents", file_name) _files = {"Filedata": open(file, 'rb')} _upload = requests.post(url, cookies=_cookie, data=_data, files=_files, stream=True) _job = self.check_response(_upload) return _job['ID'] @keyword def upload_multiple_images(self, url, file_names, _data): """ This keyword use to upload file to create job. The job ID will be returned. ``url`` (str) : webservice url. ``file_names`` (arr): Array containt all files name. ``data`` (dict): the dictionary contains transactionID, buttonID, buttonContext, sessionID """ _id = "" for _i in range(file_names.length - 1): if _i == 0: _id = self.upload_image(url, file_names[_i], _data) else: _data['transactionID'] = _id self.upload_image(url, file_names[_i], _data) return _id @keyword def download_image(self, url, file_name, _sessionID): """ This keyword use to download image from job and save as the given file name ``url`` (str) : webservice url. ``file_names`` (str): files name. """ _cookie = {"KFS_AUTH_THINCLIENT": _sessionID} _file = os.path.join(Path.home(), "Downloads", file_name) _download = requests.get(url, cookies=_cookie, stream=True) _download.raise_for_status() with open(_file, 'wb') as f: for chunk in _download.iter_content(chunk_size=128): f.write(chunk) return _file @keyword def download_web_capture(self, url, file_name, auth): """ This keyword use to download Kofax WebCapture from thinclient and save to disk as file_name. The path to downloaded file will be returned. ``url`` (str) : url to thinclient without login.html. ``file_name`` (str): path to save file. ``auth`` (dict): dictionary contains the authentication """ file_name = os.path.join(Path.home(), "Downloads", file_name) _login = requests.put(url + "/auth/", json=auth) _sessionID = _login.json()['SessionID'] _cookie = {"KFS_AUTH_THINCLIENT": _sessionID} _download = requests.get(url + "/DownloadWebCaptureServiceInstaller/", cookies=_cookie, stream=True) _download.raise_for_status() with open(file_name, 'wb') as fd: for chunk in _download.iter_content(chunk_size=128): fd.write(chunk) return file_name @keyword def get_css_property(self, locator, property_name): """ This function will return the value of the css property from the web element (defined by locator parameter) ``locator`` (WebElement locator) : the locator to identify the element ``property_name`` (str) : the name of css property to get value """ element = self.lib.find_element(locator) return element.value_of_css_property(property_name) @keyword def get_element_demention(self, locator): """ This keyword will return the demention of the image (defined by locator parameter) in array[with,height]. ``locator`` (WebElement locator) : the locator to identify the element. """ width = self.get_css_property(locator, 'width') width = int(width.rsplit('px')[0]) height = self.get_css_property(locator, 'height') height = int(height.rsplit('px')[0]) return [width, height] @keyword def document_should_be_downloaded(self): """ This keyword will check if the document is downloaded or not. """ doc = os.path.join(Path.home(), "Downloads", "document.pdf") doc_path = Path(doc) if doc_path.exists(): os.remove(doc) else: raise AssertionError( "document.pdf file is not exists in Download Folder") @keyword def border_color_should_be(self, locator, expected): """ This keyword will check the color of web element(defined by locator parameter) in format rbg(r,b,g). ``locator`` (WebElement locator) : the locator to identify the element. ``expected`` (RGB format): the rbg code Ex. rbg(0,0,0). """ color = self.get_css_property(locator, 'border-color') if (color != expected): raise AssertionError( "Actual color is '%s' while it should have been '%s'" % (color, expected)) @keyword def draw_rectangle_at_coorfinates(self, locator, top_left, bottom_right): """ This keyword use to draw a rectangle inside the web element(defined by locator parameter) from the top_left to the bottom_right. ``locator`` (WebElement locator) : the locator to identify the element. ``top_left`` (int): the top left. ``bottom_right`` (int): the bottom right. """ action = ActionChains(self.lib.driver) action.move_to_element_with_offset(self.lib.find_element(locator), top_left, top_left) action.click_and_hold().move_by_offset(bottom_right, bottom_right).release() action.perform() @keyword def area_color_should_be(self, locator, color, xoffset, yoffset): """ This keyword use to get the color (rgb format) of each pixel inside the web element(defined by locator parameter) with the top left and the bottom right after that compare with the given color (converted to rgb format). ``locator`` (string) : the locator to identify the element. ``color`` (string): the expect color (current support black/white). ``xoffset`` (int): the top left. ``yoffset`` (int): the bottom right. """ jsfile = os.path.join(os.getcwd(), "SmokeTest", "Pylibs", "GetFixelColor.js") expect = self.lib.driver.execute_script( open(jsfile).read(), locator, color, int(xoffset), int(yoffset)) if not expect: raise AssertionError("The color is not " + color + ".") @keyword def area_color_should_not_be(self, locator, color, xoffset, yoffset): """ This keyword use to get the color (rgb format) of each pixel inside the web element(defined by locator parameter) with the top left and the bottom right after that compare with the given color (converted to rgb format). ``locator`` (string) : the locator to identify the element. ``color`` (string): the expect color (current support black/white). ``xoffset`` (int): the top left. ``yoffset`` (int): the bottom right. """ jsfile = os.path.join(os.getcwd(), "SmokeTest", "Pylibs", "GetFixelColor.js") expect = self.lib.driver.execute_script( open(jsfile).read(), locator, color, int(xoffset), int(yoffset)) if expect: raise AssertionError("The color is " + color + ".") @keyword def hold_and_click(self, locator, modifier=False): """ This keyword use to hold the key before click to web element(defined by locator parameter). ``locator`` (WebElement locator) : the locator to identify the element. ``modifier`` (key): the key code. """ if not isinstance(modifier, (str)): self.lib.info("Clicking element '%s'." % locator) self.lib.find_element(locator).click() else: modifier = self.parse_modifier(modifier) action = ActionChains(self.lib.driver) for item in modifier: action.key_down(item) action.click(self.lib.find_element(locator)) for item in modifier: action.key_up(item) action.perform() @keyword def hold_and_press(self, modifier, keys): """ This keyword use to hold the modifier key before press the keys. ``keys`` (key) : the string represent the keys. ``modifier`` (key): the key code. """ modifier = self.parse_modifier(modifier) action = ActionChains(self.lib.driver) for item in modifier: action.key_down(item) action.send_keys(keys) for item in modifier: action.key_up(item) action.perform() def parse_modifier(self, modifier): modifier = modifier.upper() modifiers = modifier.split('+') keys = [] for item in modifiers: item = item.strip() if item == 'CTRL': item = 'CONTROL' if hasattr(Keys, item): keys.append(getattr(Keys, item)) else: raise ValueError( "'%s' modifier does not match to Selenium Keys" % item) return keys def check_response(self, _response): if _response.status_code != 200: raise AssertionError("Fail to send request with response code " + _response.status_code + ".") _body = _response.json() if _body['ErrorCode'] != 0: raise AssertionError("Fail to send request with error code " + _body['ErrorCode'] + ", error:" + _body['ErrorMessage']) return _body
def delete_multiple_nodes_and_wait_until_deletion(self, *args, **kwargs): """ Deletes multiple nodes/ all nodes [Args] (list) Names: List of Names of the Nodes to be deleted or Don't provide any arguments if you want to delete all nodes ... [Returns] (str) OK: Returns "OK" if all nodes are deleted successfully else: returns "Error" """ banner("Delete mutliple nodes and wait until deletion") self._load_kwargs(kwargs) conn = BuiltIn().get_variable_value("${PCC_CONN}") try: if self.Names: deletion_status = [] for name in ast.literal_eval(self.Names): node_id = self.get_node_id(Name=name) banner("Node id: {}".format(node_id)) delete_node_status = self.delete_node(Id=node_id) logger.console(delete_node_status) for name in ast.literal_eval(self.Names): deletion_response = self.wait_until_node_deleted(Name=name) deletion_status.append(deletion_response) print("deletion_status: {}".format(deletion_status)) result = len(deletion_status) > 0 and all( elem == "OK" for elem in deletion_status) if result: return "OK" else: return "Error" else: response = self.get_nodes() deletion_status_code = [] node_ready_status = [] if get_response_data(response) == None: return "OK" else: for node in get_response_data(response): deletion_response = self.delete_node(Id=node['Id']) deletion_status_code.append( deletion_response['StatusCode']) wait_until_deletion_response = self.wait_until_node_deleted( Name=node['Name']) node_ready_status.append(wait_until_deletion_response) trace("deletion_status_code: {}".format( deletion_status_code)) trace("node_ready_status: {}".format(node_ready_status)) result1 = len(deletion_status_code) > 0 and all( elem == 200 for elem in deletion_status_code) result2 = len(node_ready_status) > 0 and all( elem == "OK" for elem in node_ready_status) if result1 and result2: return "OK" else: return "Node deletion status is {} and wait until status is {}".format( deletion_status_code, node_ready_status) except Exception as e: return "Exception encountered: {}".format(e)
def open(self, filename): if self.logging_enabled: # create log file in RF output dir logname = '{}/{}'.format( BuiltIn().get_variable_value("$outputdir"), filename) self._log_handle = open(logname, 'w')
def backup_pcc_instance(self, *args, **kwargs): banner("CLI.Backup PCC Instance") self._load_kwargs(kwargs) trace("Kwargs are: " + str(kwargs)) conn = BuiltIn().get_variable_value("${PCC_CONN}") if (self.backup_type == "local") and (self.backup_params == "all"): cmd = "sudo /home/pcc/platina-cli-ws/platina-cli backup -p {}".format( self.pcc_password) if (self.backup_type == "local") and (self.backup_params != "all"): cmd = "sudo /home/pcc/platina-cli-ws/platina-cli backup -p {} -t {}".format( self.pcc_password, self.backup_params) if (self.backup_type == "remote"): cmd = "sudo /home/pcc/platina-cli-ws/platina-cli backup -p {} --url http://{}:9001 --id minio --secret minio123".format( self.pcc_password, self.backup_hostip) print("Command: " + str(cmd) + " is getting executed") trace("Command: " + str(cmd) + " is getting executed") cmd_op = cli_run(self.host_ip, self.linux_user, self.linux_password, cmd) print("cmd op: {}".format(str(cmd_op))) if re.search("FAIL", str(cmd_op)): print("Failed to backup, result is: \n {}".format(str(cmd_op))) BuiltIn().fatal_error( 'Stoping the exectuion, Backup not succeded !!!') return "Error: Failed to backup" else: cmd_file = "sudo test -f /home/pcc/platina-cli-ws/master.gpg && echo 'True' || echo 'False'" cmd_out = cli_run(self.host_ip, self.linux_user, self.linux_password, cmd_file) print("Checking if keys exist or not:" + str(cmd_out)) if re.search("True", str(cmd_out)): if self.backup_type == "local": cmd_local_file = "sudo test -d /home/pcc/platina-cli-ws/keys/local && echo 'True' || echo 'False'" cmd_out = cli_run(self.host_ip, self.linux_user, self.linux_password, cmd_local_file) print("Checking if keys folder exist or not:" + str(cmd_out)) if re.search("False", str(cmd_out)): folder_cmd = "sudo mkdir -p /home/pcc/platina-cli-ws/keys/local" cmd_out = cli_run(self.host_ip, self.linux_user, self.linux_password, folder_cmd) print("Folder check:" + str(cmd_out)) move_cmd = "sudo mv /home/pcc/platina-cli-ws/*.gpg /home/pcc/platina-cli-ws/keys/local/." cmd_out = cli_run(self.host_ip, self.linux_user, self.linux_password, move_cmd) print("Key moving:" + str(cmd_out)) else: move_cmd = "sudo mv /home/pcc/platina-cli-ws/*.gpg /home/pcc/platina-cli-ws/keys/local/." cmd_out = cli_run(self.host_ip, self.linux_user, self.linux_password, move_cmd) print("Key moving:" + str(cmd_out)) elif self.backup_type == "remote": cmd = "sudo test -d /home/pcc/platina-cli-ws/keys/remote && echo 'True' || echo 'False'" cmd_out = cli_run(self.host_ip, self.linux_user, self.linux_password, cmd) print("Checking if keys folder exist or not:" + str(cmd_out)) if re.search("False", str(cmd_out)): folder_cmd = "sudo mkdir -p /home/pcc/platina-cli-ws/keys/remote" cmd_out = cli_run(self.host_ip, self.linux_user, self.linux_password, folder_cmd) move_cmd = "sudo mv /home/pcc/platina-cli-ws/*.gpg /home/pcc/platina-cli-ws/keys/remote/." print("Folder check:" + str(cmd_out)) cmd_out = cli_run(self.host_ip, self.linux_user, self.linux_password, move_cmd) print("Key moving:" + str(cmd_out)) else: move_cmd = "sudo mv /home/pcc/platina-cli-ws/*.gpg /home/pcc/platina-cli-ws/keys/remote/." cmd_out = cli_run(self.host_ip, self.linux_user, self.linux_password, move_cmd) print("Key moving:" + str(cmd_out)) return "OK"
def _expose_instance(name, instance): BuiltIn().set_test_variable('${created %s}' % name, instance)
import sys import os import time sys.path.append(os.path.join(os.path.dirname(__file__), '..', '../libraries/common')) from datetime import datetime # noqa from datetime import timedelta # noqa from robot.libraries.BuiltIn import BuiltIn # noqa from robot.api import logger # noqa import common_utils # noqa from decorators_for_robot_functionalities import * # noqa from test_constants import * # noqa execute = BuiltIn().get_library_instance('execute_command') stack_infos = BuiltIn().get_library_instance('stack_infos') def HPA_check(): steps = ['step1_check_initial_replica_count', 'step2_check_scale_out', 'step3_check_scale_in'] BuiltIn().run_keyword("HPA_check.setup") common_utils.keyword_runner(steps) def setup(): common_utils.helm_install(chart_name="default/php-apache", release_name="crf01", values="registry_url={reg_url}".format(reg_url=reg)) common_utils.check_kubernetes_object(kube_object=php_apache_pod, tester_function=common_utils.test_kubernetes_object_available, additional_filter="Running",