How to use update_config_variable method in localstack

Best Python code snippet using localstack_python

start.py

Source:start.py Github

copy

Full Screen

...82 print(config.LIMIT)83 print(config.get_config_variable(key="limit_topic"))84 if config.LIMIT["LIMIT_TOPIC"] >= len(config.SUB_TOPIC) :85 if str(passkey) == str(config.PIN_DEVICE):86 config.update_config_variable(key='sub_topic', value=[id_topic, name_home, name_topic], arr_op="ADD", reload_variables=True)87 client.subscribe(id_topic)88 d = {}89 d[ smac_keys["ID_TOPIC"] ] = id_topic90 d[ smac_keys["NAME_DEVICE"]] = config.NAME_DEVICE91 d[ smac_keys["TYPE_DEVICE"]] = config.TYPE_DEVICE92 d[ smac_keys["NAME_HOME"]] = name_home93 d[ smac_keys["NAME_TOPIC"]] = name_topic94 client.send_message(frm=config.ID_DEVICE, to="#", cmd=smac_keys["CMD_STATUS_ADD_TOPIC"], message=d, udp=True, tcp=False)95 # sending ACK96 d1 = {}97 d1[ smac_keys["MESSAGE"] ] = "Topic subscribed successfylly"98 print("subscribed topic: {}".format(id_topic))99 else:100 d1 = {}101 d1[smac_keys["MESSAGE"]] = "Topic '{}' not subscribed".format(id_topic)102 d1[smac_keys["ID_DEVICE"]] = id_device103 d1[smac_keys["ID_TOPIC"]] = id_topic104 print("Cannot subscribe to {}. Passkey error.".format(id_topic))105 if config.ID_DEVICE == frm:106 print("same device")107 else:108 client.send_message(frm=config.ID_DEVICE, to=frm, cmd=smac_keys["CMD_INVALID_PIN"], message=d1, udp=True, tcp=False)109 #client.send_message(frm=config.ID_DEVICE, to=id_topic, cmd=smac_keys["CMD_INVALID_PIN"], message=d1)110 else:111 d1 = {}112 d1[smac_keys["MESSAGE"]] = "Topic '{}/{}' not subscribed. Topic Limit Reached.".format(name_home, name_topic)113 d1[smac_keys["ID_DEVICE"]] = id_device114 d1[smac_keys["ID_TOPIC"]] = id_topic115 print("Cannot subscribe to {}. Topic Limit Reached.".format(id_topic))116 if config.ID_DEVICE == frm:117 print("same device")118 else:119 client.send_message(frm=config.ID_DEVICE, to=frm, cmd=smac_keys["CMD_TOPIC_LIMIT_EXCEEDED"], message=d1)120 def delete_topic(self, frm, id_topic, id_device, passkey, *args):121 print(passkey)122 print(config.PIN_DEVICE)123 print(passkey == config.PIN_DEVICE)124 #print(type(passkey))125 #print(type(config.PIN_DEVICE))126 if str(passkey) == str(config.PIN_DEVICE):127 #db.add_network_entry(name_topic=id_topic, id_topic=id_topic, id_device=id_device, name_device=self.NAME_DEVICE, type_device=self.TYPE_DEVICE)128 #db.delete_network_entry_by_topic(id_topic, id_device)129 config.update_config_variable(key='sub_topic', value=id_topic, arr_op="REM", reload_variables=True)130 client.unsubscribe(id_topic)131 #self.delete_topic_widget(id_topic)132 d = {}133 d[ smac_keys["ID_TOPIC"] ] = id_topic134 d[ smac_keys["NAME_DEVICE"]] = config.NAME_DEVICE135 d[ smac_keys["TYPE_DEVICE"]] = config.TYPE_DEVICE136 client.send_message(frm=config.ID_DEVICE, to="#", cmd=smac_keys["CMD_STATUS_REMOVE_TOPIC"], message=d, udp=True, tcp=False)137 # sending ACK138 d1 = {}139 d1[ smac_keys["MESSAGE"] ] = "Topic unsubscribed successfylly"140 print("unsubscribed topic: {}".format(id_topic))141 else:142 d1 = {}143 d1[smac_keys["MESSAGE"]] = "Topic '{}' not unsubscribed".format(id_topic)144 d1[smac_keys["ID_DEVICE"]] = id_device145 d1[smac_keys["ID_TOPIC"]] = id_topic146 print("Cannot unsubscribe to {}. Passkey error.".format(id_topic))147 if config.ID_DEVICE == frm:148 print("same device")149 else:150 client.send_message(frm=config.ID_DEVICE, to=frm, cmd=smac_keys["CMD_INVALID_PIN"], message=d1, udp=True, tcp=False)151 def on_message(self, topic, message, protocol, *args):152 #print(args)153 try:154 print( "{}, {}, {}".format(topic, message, protocol) )155 msg = json.loads(message)156 #print("1")157 frm = msg.get( smac_keys["FROM"] , None)158 to = msg.get( smac_keys["TO"], None)159 cmd = msg.get( smac_keys["COMMAND"], None )160 ack = msg.get( smac_keys["ACK"], None )161 msg_id = msg.get( smac_keys["ID_MESSAGE"], None )162 #data = msg.get( smac_keys["MESSAGE"], None )163 data = msg164 #print("2")165 #print(data)166 if frm != config.ID_DEVICE:167 if cmd == smac_keys["CMD_SET_PROPERTY"]:168 #print("3")169 id_prop = msg.get( smac_keys["ID_PROPERTY"], None)170 type_prop = msg.get( smac_keys["TYPE_PROPERTY"], None)171 #instance = data.get( smac_keys["INSTANCE"], None )172 value = msg.get( smac_keys["VALUE"], 0 )173 #print("4")174 if type_prop == SMAC_PROPERTY["SWITCH"]:175 #print("5")176 value = value if(type(value) == int) else int(value)177 config.update_config_variable(key=id_prop, value=value)178 config.update_config_variable(key=str(id_prop) + "_time", value=time.time())179 '''if value:180 #config.PROP["{}:{}".format(prop, instance) ].on()181 config.PROP_INSTANCE[id_prop].on()182 #print("6")183 else:184 #config.PROP["{}:{}".format(prop, instance) ].off()185 config.PROP_INSTANCE[id_prop].off()186 d = {}187 d[smac_keys["ID_PROPERTY"]] = id_prop188 d[smac_keys["ID_DEVICE"]] = config.ID_DEVICE189 d[smac_keys["VALUE"]] = value190 #topics = config.SUB_TOPIC191 #for id_topic in topics:192 #client.send_message(frm=config.ID_DEVICE, to="#", message=d, cmd=smac_keys["CMD_STATUS_SET_PROPERTY"], udp=True, tcp=False)193 client.send_message(frm=config.ID_DEVICE, to="#", message=d, cmd=smac_keys["CMD_STATUS_SET_PROPERTY"], udp=True, tcp=False)'''194 if cmd == smac_keys["CMD_REQ_SEND_INFO"]:195 print(self.SENDING_INFO)196 #if not self.SEND_INFO:197 print("sending device info...")198 try:199 #self.send_device_info( dest_topic=frm)200 self.send_device_info( dest_topic="#")201 except Exception as e:202 raise e203 if cmd == smac_keys["CMD_ADD_TOPIC"]:204 id_topic = data.get(smac_keys["ID_TOPIC"])205 id_device = data.get(smac_keys["ID_DEVICE"])206 passkey = data.get(smac_keys["PASSKEY"])207 name_home = data.get(smac_keys["NAME_HOME"])208 name_topic = data.get(smac_keys["NAME_TOPIC"])209 self.add_topic(frm, id_topic, name_home, name_topic, id_device, passkey, msg_id)210 #self.ACKS.append( "{}:{}:{}".format(id_topic, id_device, smac_keys["CMD_ADD_TOPIC"]) )211 if cmd == smac_keys["CMD_REMOVE_TOPIC"]:212 id_topic = data.get(smac_keys["ID_TOPIC"])213 id_device = data.get(smac_keys["ID_DEVICE"])214 passkey = data.get(smac_keys["PASSKEY"])215 self.delete_topic(frm, id_topic, id_device, passkey, msg_id)216 if cmd == smac_keys["CMD_UPDATE_WIFI_CONFIG"]:217 ssid = data.get(smac_keys["SSID"])218 password = data.get(smac_keys["PASSWORD"])219 passkey = data.get(smac_keys["PASSKEY"])220 if str(config.PIN_DEVICE) == str(passkey):221 config.update_config_variable(key="wifi_config_2", value={"ssid": ssid, "password": password})222 client.send_message(frm=config.ID_DEVICE, to=frm, cmd=smac_keys["CMD_STATUS_UPDATE_WIFI_CONFIG"],message={}, udp=True, tcp=False)223 else:224 d1 = {}225 d1[smac_keys["MESSAGE"]] = "WIFI CONFIG not updated. Passkey Error"226 #d1[smac_keys["ID_DEVICE"]] = frm227 #d1[smac_keys["ID_TOPIC"]] = id_topic228 print("WIFI CONFIG not updated. Passkey Error")229 client.send_message(frm=config.ID_DEVICE, to=frm, cmd=smac_keys["CMD_INVALID_PIN"],230 message=d1, udp=True, tcp=False)231 if cmd == smac_keys["CMD_UPDATE_SOFTWARE"]:232 config.update_config_variable(key="mode", value=1)233 config.update_config_variable(key="download_software", value=1)234 config.update_config_variable(key="download_software_requested_by", value=frm)235 print("Restarting")236 time.sleep(1)237 machine.reset()238 if cmd == smac_keys["CMD_UPDATE_INTERVAL_ONLINE"]:239 interval = data.get(smac_keys["INTERVAL"])240 passkey = data.get(smac_keys["PASSKEY"])241 id_device = data.get(smac_keys["ID_DEVICE"])242 if id_device == config.ID_DEVICE:243 if str(config.PIN_DEVICE) == str(passkey):244 config.update_config_variable(key="interval_online", value=interval)245 d1 = {}246 d1[smac_keys["INTERVAL"]] = interval247 d1[smac_keys["ID_DEVICE"]] = id_device248 client.send_message(frm=config.ID_DEVICE, to=frm, cmd=smac_keys["CMD_STATUS_UPDATE_INTERVAL_ONLINE"],message=d1, udp=True, tcp=False)249 else:250 d1 = {}251 d1[smac_keys["MESSAGE"]] = "Online Interval not updated. Passkey Error"252 #d1[smac_keys["ID_DEVICE"]] = config.ID_DEVICE253 #d1[smac_keys["ID_TOPIC"]] = id_topic254 print(d1[smac_keys["MESSAGE"]])255 client.send_message(frm=config.ID_DEVICE, to=frm, cmd=smac_keys["CMD_INVALID_PIN"],256 message=d1, udp=True, tcp=False)257 if cmd == smac_keys["CMD_UPDATE_NAME_DEVICE"]:258 name_device = data.get(smac_keys["NAME_DEVICE"])259 id_device = data.get(smac_keys["ID_DEVICE"])260 if id_device == config.ID_DEVICE:261 passkey = data.get(smac_keys["PASSKEY"])262 if str(config.PIN_DEVICE) == str(passkey):263 config.update_config_variable(key="NAME_DEVICE", value=name_device)264 config.NAME_DEVICE = name_device265 d1 = {}266 d1[smac_keys["NAME_DEVICE"]] = name_device267 d1[smac_keys["ID_DEVICE"]] = id_device268 client.send_message(frm=config.ID_DEVICE, to=frm, cmd=smac_keys["CMD_STATUS_UPDATE_NAME_DEVICE"],message=d1, udp=True, tcp=False)269 else:270 d1 = {}271 d1[smac_keys["MESSAGE"]] = "Device Name not updated. Passkey Error"272 #d1[smac_keys["ID_DEVICE"]] = config.ID_DEVICE273 #d1[smac_keys["ID_TOPIC"]] = id_topic274 print(d1[smac_keys["MESSAGE"]])275 client.send_message(frm=config.ID_DEVICE, to=frm, cmd=smac_keys["CMD_INVALID_PIN"],276 message=d1, udp=True, tcp=False)277 if cmd == smac_keys["CMD_UPDATE_NAME_PROPERTY"]:278 name_property = data.get(smac_keys["NAME_PROPERTY"])279 id_property = data.get(smac_keys["ID_PROPERTY"])280 id_device = data.get(smac_keys["ID_DEVICE"])281 if id_device == config.ID_DEVICE:282 passkey = data.get(smac_keys["PASSKEY"])283 d1 = {}284 d1[smac_keys["NAME_PROPERTY"]] = name_property285 d1[smac_keys["ID_PROPERTY"]] = id_property286 d1[smac_keys["ID_DEVICE"]] = id_device287 if str(config.PIN_DEVICE) == str(passkey):288 config.update_name_property(id_property, name_property)289 client.send_message(frm=config.ID_DEVICE, to=frm, cmd=smac_keys["CMD_STATUS_UPDATE_NAME_PROPERTY"],message=d1, udp=True, tcp=False)290 else:291 d1[smac_keys["MESSAGE"]] = "Property Name not updated. Passkey Error"292 #d1[smac_keys["ID_DEVICE"]] = config.ID_DEVICE293 #d1[smac_keys["ID_TOPIC"]] = id_topic294 print(d1[smac_keys["MESSAGE"]])295 client.send_message(frm=config.ID_DEVICE, to=frm, cmd=smac_keys["CMD_INVALID_PIN"],296 message=d1, udp=True, tcp=False)297 except Exception as e:298 print("Exception while decoding message: {}".format(e) )299 # raise e300 async def interval(self):301 await asyncio.sleep(0)302 COUNTER = 0303 while 1:304 #print(self.PROPERTY)305 for num, prop in enumerate(self.PROPERTY):306 value = prop["value"]307 id_prop = prop["id_property"]308 type_prop = prop["type_property"]309 value_temp = config.get_config_variable(key=id_prop)310 #print(prop)311 #print(value)312 #print(value_temp)313 if value_temp != value:314 lastUpdated_time = config.get_config_variable(key=str(id_prop) + "_time")315 if lastUpdated_time == None:316 lastUpdated_time = time.time()317 t_diff = time.time() - lastUpdated_time318 print("t_diff", t_diff)319 if t_diff > .5:320 self.set_property(id_prop, type_prop, value_temp)321 #print("before")322 #print(self.PROPERTY)323 self.PROPERTY[num]["value"] = value_temp324 #print("after")325 #print(self.PROPERTY)326 else:327 print("Device is Busy")328 d = {}329 d[smac_keys["ID_DEVICE"]] = config.ID_DEVICE330 d[smac_keys["VALUE"]] = 5331 #client.send_message(frm=config.ID_DEVICE, to="#", cmd=smac_keys["CMD_DEVICE_BUSY"], message=d, udp=True, tcp=False)332 if(COUNTER % (10*config.INTERVAL_ONLINE)) == 0:333 client.send_message(frm=config.ID_DEVICE, to="#", cmd=smac_keys["CMD_ONLINE"], message={}, udp=True,334 tcp=False)335 COUNTER += 1336 await asyncio.sleep(.1)337 def set_property(self, id_prop, type_prop, value):338 try:339 if type_prop == SMAC_PROPERTY["SWITCH"]:340 #config.update_config_variable(key=id_prop, value=value)341 if value:342 config.PROP_INSTANCE[id_prop].on()343 else:344 config.PROP_INSTANCE[id_prop].off()345 if type_prop == SMAC_PROPERTY["FAN"]:346 config.PROP_INSTANCE[id_prop].change_speed(value)347 d = {}348 d[smac_keys["ID_PROPERTY"]] = id_prop349 d[smac_keys["ID_DEVICE"]] = config.ID_DEVICE350 d[smac_keys["VALUE"]] = value351 client.send_message(frm=config.ID_DEVICE, to="#", message=d, cmd=smac_keys["CMD_STATUS_SET_PROPERTY"],352 udp=True, tcp=False)353 except Exception as e:354 print("Exception during set_property: {}".format(e) )355 async def start(self):356 if config.ID_DEVICE== "":357 req_get_device_id()358 time.sleep(2)359 topics = [ t[0] for t in config.SUB_TOPIC ]360 client.subscribe( ["#", config.ID_DEVICE ]+topics )361 print(client.SUB_TOPIC)362 #client.subscribe( "D1" )363 #client.subscribe( "D2" )364 client.process_message = self.on_message365 download_software_status = config.get_config_variable(key="download_software_status")366 if download_software_status != None:367 config.delete_config_variable(key="download_software_status")368 dest_topic = config.get_config_variable(key="download_software_requested_by")369 d = {}370 if download_software_status == "0":371 d[smac_keys["MESSAGE"]] = "No updates available"372 client.send_message(frm=config.ID_DEVICE, to=dest_topic, cmd=smac_keys["CMD_STATUS_UPDATE_SOFTWARE"], message=d, udp=True, tcp=False)373 elif download_software_status == "1":374 d[smac_keys["MESSAGE"]] = "New Updates Downloaded and Installed."375 client.send_message(frm=config.ID_DEVICE, to=dest_topic, cmd=smac_keys["CMD_STATUS_UPDATE_SOFTWARE"], message=d, udp=True, tcp=False)376 if ESP:377 with open("device.json", "r") as f:378 try:379 f1 = json.loads(f.read())380 self.PROPERTY = f1381 for p in f1:382 #print(p)383 id_prop = p["id_property"]384 type_prop = p["type_property"]385 #instance = p["instance"]386 ip_pin = p["pin_input"]387 ip_pin = ip_pin.split(",")388 op_pin = p["pin_output"]389 op_pin = op_pin.split(",")390 pre_val = config.get_config_variable("{}".format(id_prop))391 config.update_config_variable(key=id_prop+"_time", value=time.time())392 print("prevel: {}".format(pre_val))393 if type_prop == SMAC_PROPERTY["FAN"]:394 #config.PROP["{}:{}".format(prop, instance)] = Fan( input=ip_pin[0], output=op_pin, value=pre_val )395 config.PROP_INSTANCE[id_prop] = Fan( input=ip_pin[0], output=op_pin, value=pre_val )396 elif type_prop == SMAC_PROPERTY["SWITCH"]:397 #config.PROP["{}:{}".format(prop, instance)] = Switch( input=ip_pin[0], output=op_pin[0], value=pre_val )398 config.PROP_INSTANCE[id_prop] = Switch( input=ip_pin[0], output=op_pin[0], value=pre_val )399 except Exception as e:400 print("error ip config: {}".format(e))401 #t1 = asyncio.ensure_future( self.send_test() )402 #t2 = asyncio.ensure_future( client.main() )403 if ESP:404 self.send_device_info(dest_topic="#")405 t1 = asyncio.create_task(client.main())...

Full Screen

Full Screen

web_server.py

Source:web_server.py Github

copy

Full Screen

...72 v = req.form73 conn = req.form["connection"]74 key_ = "wifi_config_1" if(conn == '1') else "wifi_config_2"75 yield from picoweb.start_response(resp)76 config.update_config_variable(key=key_, value=req.form )77 yield from resp.awrite("Wifi config updated successfully")78@app.route("/update_mqtt_server")79def update_mqtt_server(req, resp):80 if req.method == "POST":81 yield from req.read_form_data()82 else: # GET, apparently83 req.parse_qs()84 print(req.form)85 yield from picoweb.start_response(resp)86 config.update_config_variable(key="mqtt_server", value=req.form["mqtt_server"] )87 yield from resp.awrite("Mqtt Server updated successfully")88@app.route("/update_name_device")89def update_name_device(req, resp):90 if req.method == "POST":91 yield from req.read_form_data()92 else: # GET, apparently93 req.parse_qs()94 print(req.form)95 yield from picoweb.start_response(resp)96 config.update_config_variable(key="name_device", value=req.form["name_device"] )97 yield from resp.awrite("Device Name updated successfully")98@app.route("/remove_topic")99def remove_topic(req, resp):100 if req.method == "POST":101 yield from req.read_form_data()102 else: # GET, apparently103 req.parse_qs()104 #print("req.form",req.form)105 #print("req.form.keys", req.form.keys())106 print( json.loads(req.form["sub_topic"]) )107 yield from picoweb.start_response(resp)108 for topic in json.loads(req.form["sub_topic"]):109 config.update_config_variable(key="sub_topic", value=topic, arr_op="REM" )110 yield from resp.awrite("Device Name updated successfully")111@app.route("/update_pin_device")112def update_pin_device(req, resp):113 if req.method == "POST":114 yield from req.read_form_data()115 else: # GET, apparently116 req.parse_qs()117 print(req.form)118 yield from picoweb.start_response(resp)119 config.update_config_variable(key="pin_device", value=req.form["pin_device"] )120 yield from resp.awrite("Device PIN updated successfully")121def http_get(url, https=True):122 import socket123 import ssl124 _, _, host, path = url.split('/', 3)125 print(host)126 print(path)127 128 #addr = socket.getaddrinfo(host, 80)[0][-1]129 #print(addr)130 s = socket.socket()131 port = 443 if https else 80132 s.connect( (host, port) )133 cmd = "GET https://smacsystem.com/download/esp32/version.js HTTP/1.0\r\n\r\n".encode()134 if https:135 136 s = ssl.wrap_socket(s)137 s.write(cmd)138 #s.send(bytes('GET /%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n' % (path, host), 'utf8'))139 data = ""140 while True:141 data = s.recv(100)142 if data:143 print("a\n")144 print(str(data, 'utf8'), end='')145 else:146 break147 s.close()148 print("res\n")149 #return str(data, 'utf8')150@app.route("/restart")151def restart(req, resp):152 print("restarting")153 if req.method == "POST":154 yield from req.read_form_data()155 else: # GET, apparently156 req.parse_qs()157 mode = req.form.get("mode", 0)158 config.update_config_variable(key="mode", value=mode )159 machine.reset()160@app.route("/download_update")161def download_update(req, resp):162 if req.method == "POST":163 yield from req.read_form_data()164 else: # GET, apparently165 req.parse_qs()166 print(req.form)167 version = req.form["version"]168 ota.download_all_files(version=version)169 config.delete_config_variable(key="download_version")170 yield from picoweb.start_response(resp)171 yield from resp.awrite("Updates installed. Restarting")172 config.update_config_variable(key="mode", value=0)173 machine.reset()174@app.route("/check_for_update")175def check_for_update(req, resp):176 if req.method == "POST":177 yield from req.read_form_data()178 else: # GET, apparently179 req.parse_qs()180 new_updates = ota.check_for_latest_version()181 if new_updates:182 yield from picoweb.start_response(resp)183 yield from resp.awrite("New Updates available")184 else:185 yield from picoweb.http_error(resp, "400")186 yield from resp.awrite("Device is already upto date.")...

Full Screen

Full Screen

update_config_variable.py

Source:update_config_variable.py Github

copy

Full Screen

1import json2from airflow import DAG3from airflow.operators.dummy import DummyOperator4from airflow.operators.python import PythonOperator5from airflow.providers.postgres.hooks.postgres import PostgresHook6from airflow.providers.postgres.operators.postgres import PostgresOperator7from datetime import datetime8from airflow.models import Variable9def update_dag_config():10 postgres_hook = PostgresHook(postgres_conn_id="airflow_db")11 df = postgres_hook.get_pandas_df(sql="select * from public.dag_config;")12 result = df.to_json(orient="records")13 parsed = json.loads(result)14 final = json.dumps(parsed, indent=4)15 print(final)16 try:17 Variable.update(key="dag_config", value=final)18 except:19 Variable.set(key="dag_config", value=final)20default_args = {21 'owner': 'airflow',22 'start_date': datetime(2021, 1, 1),23 'catchup': False24}25with DAG(26 dag_id='update_config_variable',27 schedule_interval=None,28 default_args=default_args,29 template_searchpath="/usr/local/airflow/include/update_config_variable/",30 catchup=False,31 ) as dag:32 start = DummyOperator(33 task_id="start"34 )35 finish = DummyOperator(36 task_id="finish"37 )38 t1 = PostgresOperator(39 task_id="initialize_config",40 sql="initialize_config.sql",41 postgres_conn_id='airflow_db'42 )43 t2 = PythonOperator(44 task_id='update_dag_config',45 python_callable=update_dag_config,46 )...

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run localstack automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful