Best Python code snippet using robotframework
__init__.py
Source:__init__.py
1import collections2import itertools3import logging4from typing import Optional5from archinfo import ArchSoot6from claripy import BVV, StrSubstr7from ...calling_conventions import DefaultCC8from ...sim_procedure import SimProcedure9from ...sim_type import SimTypeFunction10from ...state_plugins.sim_action_object import SimActionObject11l = logging.getLogger('angr.procedures.java_jni')12class JNISimProcedure(SimProcedure):13 """14 Base SimProcedure class for JNI interface functions.15 """16 # Java type of return value17 return_ty = None # type: Optional[str]18 # jboolean constants19 JNI_TRUE = 120 JNI_FALSE = 021 def execute(self, state, successors=None, arguments=None, ret_to=None):22 # Setup a SimCC using the correct type for the return value23 if not self.return_ty:24 raise ValueError("Classes implementing JNISimProcedure's must set the return type.")25 elif self.return_ty != 'void':26 func_ty = SimTypeFunction(args=[],27 returnty=state.project.simos.get_native_type(self.return_ty))28 self.cc = DefaultCC[state.arch.name](state.arch, func_ty=func_ty)29 super(JNISimProcedure, self).execute(state, successors, arguments, ret_to)30 #31 # Memory32 #33 def _allocate_native_memory(self, size):34 return self.state.project.loader.extern_object.allocate(size=size)35 def _store_in_native_memory(self, data, data_type, addr=None):36 """37 Store in native memory.38 :param data: Either a single value or a list.39 Lists get interpreted as an array.40 :param data_type: Java type of the element(s).41 :param addr: Native store address.42 If not set, native memory is allocated.43 :return: Native addr of the stored data.44 """45 # check if addr is symbolic46 if addr is not None and self.state.solver.symbolic(addr):47 raise NotImplementedError('Symbolic addresses are not supported.')48 # lookup native size of the type49 type_size = ArchSoot.sizeof[data_type]50 native_memory_endness = self.state.arch.memory_endness51 # store single value52 if isinstance(data, int):53 if addr is None:54 addr = self._allocate_native_memory(size=type_size//8)55 value = self.state.solver.BVV(data, type_size)56 self.state.memory.store(addr, value, endness=native_memory_endness)57 # store array58 elif isinstance(data, list):59 if addr is None:60 addr = self._allocate_native_memory(size=type_size*len(data)//8)61 for idx, value in enumerate(data):62 memory_addr = addr+idx*type_size//863 self.state.memory.store(memory_addr, value, endness=native_memory_endness)64 # return native addr65 return addr66 def _load_from_native_memory(self, addr, data_type=None, data_size=None,67 no_of_elements=1, return_as_list=False):68 """69 Load from native memory.70 :param addr: Native load address.71 :param data_type: Java type of elements.72 If set, all loaded elements are casted to this type.73 :param data_size: Size of each element.74 If not set, size is determined based on the given type.75 :param no_of_elements: Number of elements to load.76 :param return_as_list: Whether to wrap a single element in a list.77 :return: The value or a list of loaded element(s).78 """79 # check if addr is symbolic80 if addr is not None and self.state.solver.symbolic(addr):81 raise NotImplementedError('Symbolic addresses are not supported.')82 # if data size is not set, derive it from the type83 if not data_size:84 if data_type:85 data_size = ArchSoot.sizeof[data_type]//886 else:87 raise ValueError("Cannot determine the data size w/o a type.")88 native_memory_endness = self.state.arch.memory_endness89 # load elements90 values = []91 for i in range(no_of_elements):92 value = self.state.memory.load(addr + i*data_size,93 size=data_size,94 endness=native_memory_endness)95 if data_type:96 value = self.state.project.simos.cast_primitive(self.state, value=value, to_type=data_type)97 values.append(value)98 # return element(s)99 if no_of_elements == 1 and not return_as_list:100 return values[0]101 else:102 return values103 def _load_string_from_native_memory(self, addr_):104 """105 Load zero terminated UTF-8 string from native memory.106 :param addr_: Native load address.107 :return: Loaded string.108 """109 # check if addr is symbolic110 if self.state.solver.symbolic(addr_):111 l.error("Loading strings from symbolic addresses is not implemented. "112 "Continue execution with an empty string.")113 return ""114 addr = self.state.solver.eval(addr_)115 # load chars one by one116 chars = []117 for i in itertools.count():118 str_byte = self.state.memory.load(addr+i, size=1)119 if self.state.solver.symbolic(str_byte):120 l.error("Loading of strings with symbolic chars is not supported. "121 "Character %d is concretized.", i)122 str_byte = self.state.solver.eval(str_byte)123 if str_byte == 0:124 break125 chars.append(chr(str_byte))126 return "".join(chars)127 def _store_string_in_native_memory(self, string, addr=None):128 """129 Store given string UTF-8 encoded and zero terminated in native memory.130 :param str string: String131 :param addr: Native store address.132 If not set, native memory is allocated.133 :return: Native address of the string.134 """135 if addr is None:136 addr = self._allocate_native_memory(size=len(string)+1)137 else:138 # check if addr is symbolic139 if self.state.solver.symbolic(addr):140 l.error("Storing strings at symbolic addresses is not implemented. "141 "Continue execution with concretized address.")142 addr = self.state.solver.eval(addr)143 # warn if string is symbolic144 if self.state.solver.symbolic(string):145 l.warning('Support for symbolic strings, passed to native code, is limited. '146 'String will get concretized after `ReleaseStringUTFChars` is called.')147 # store chars one by one148 str_len = len(string) // 8149 for idx in range(str_len):150 str_byte = StrSubstr(idx, 1, string)151 self.state.memory.store(addr+idx, str_byte)152 # store terminating zero153 self.state.memory.store(len(string), BVV(0, 8))154 return addr155 #156 # MISC157 #158 def _normalize_array_idx(self, idx):159 """160 In Java, all array indices are represented by a 32 bit integer and161 consequently we are using in the Soot engine a 32bit bitvector for this.162 This function normalize the given index to follow this "convention".163 :return: Index as a 32bit bitvector.164 """165 if isinstance(idx, SimActionObject):166 idx = idx.to_claripy()167 if self.arch.memory_endness == "Iend_LE":168 return idx.reversed.get_bytes(index=0, size=4).reversed169 else:170 return idx.get_bytes(index=0, size=4)171#172# JNI function table173# => Map all interface function to the name of their corresponding SimProcedure174jni_functions = collections.OrderedDict() # type: collections.OrderedDict[str, str]175not_implemented = "UnsupportedJNIFunction"176# Reserved Entries177jni_functions["reserved0"] = not_implemented178jni_functions["reserved1"] = not_implemented179jni_functions["reserved2"] = not_implemented180jni_functions["reserved3"] = not_implemented181# Version Information182jni_functions["GetVersion"] = "GetVersion"183# Class and Interface Operations184jni_functions["DefineClass"] = not_implemented185jni_functions["FindClass"] = "FindClass"186jni_functions["FromReflectedMethod"] = not_implemented187jni_functions["FromReflectedField"] = not_implemented188jni_functions["ToReflectedMethod"] = not_implemented189jni_functions["GetSuperclass"] = "GetSuperclass"190jni_functions["IsAssignableFrom"] = not_implemented191jni_functions["ToReflectedField"] = not_implemented192# Exceptions193jni_functions["Throw"] = not_implemented194jni_functions["ThrowNew"] = not_implemented195jni_functions["ExceptionOccurred"] = not_implemented196jni_functions["ExceptionDescribe"] = not_implemented197jni_functions["ExceptionClear"] = not_implemented198jni_functions["FatalError"] = not_implemented199# Global and Local References200jni_functions["PushLocalFrame"] = not_implemented201jni_functions["PopLocalFrame"] = not_implemented202jni_functions["NewGlobalRef"] = "NewGlobalRef"203jni_functions["DeleteGlobalRef"] = "DeleteGlobalRef"204jni_functions["DeleteLocalRef"] = "DeleteLocalRef"205# Object Operations206jni_functions["IsSameObject"] = "IsSameObject"207jni_functions["NewLocalRef"] = "NewLocalRef"208jni_functions["EnsureLocalCapacity"] = not_implemented209jni_functions["AllocObject"] = "AllocObject"210jni_functions["NewObject"] = "NewObject"211jni_functions["NewObjectV"] = not_implemented212jni_functions["NewObjectA"] = not_implemented213jni_functions["GetObjectClass"] = "GetObjectClass"214jni_functions["IsInstanceOf"] = "IsInstanceOf"215# Instance Method Calls216jni_functions["GetMethodID"] = "GetMethodID"217jni_functions["CallObjectMethod"] = "CallObjectMethod"218jni_functions["CallObjectMethodV"] = not_implemented219jni_functions["CallObjectMethodA"] = "CallObjectMethodA"220jni_functions["CallBooleanMethod"] = "CallBooleanMethod"221jni_functions["CallBooleanMethodV"] = not_implemented222jni_functions["CallBooleanMethodA"] = "CallBooleanMethodA"223jni_functions["CallByteMethod"] = "CallByteMethod"224jni_functions["CallByteMethodV"] = not_implemented225jni_functions["CallByteMethodA"] = "CallByteMethodA"226jni_functions["CallCharMethod"] = "CallCharMethod"227jni_functions["CallCharMethodV"] = not_implemented228jni_functions["CallCharMethodA"] = "CallCharMethodA"229jni_functions["CallShortMethod"] = "CallShortMethod"230jni_functions["CallShortMethodV"] = not_implemented231jni_functions["CallShortMethodA"] = "CallShortMethodA"232jni_functions["CallIntMethod"] = "CallIntMethod"233jni_functions["CallIntMethodV"] = not_implemented234jni_functions["CallIntMethodA"] = "CallIntMethodA"235jni_functions["CallLongMethod"] = "CallLongMethod"236jni_functions["CallLongMethodV"] = not_implemented237jni_functions["CallLongMethodA"] = "CallLongMethodA"238jni_functions["CallFloatMethod"] = not_implemented239jni_functions["CallFloatMethodV"] = not_implemented240jni_functions["CallFloatMethodA"] = not_implemented241jni_functions["CallDoubleMethod"] = not_implemented242jni_functions["CallDoubleMethodV"] = not_implemented243jni_functions["CallDoubleMethodA"] = not_implemented244jni_functions["CallVoidMethod"] = "CallVoidMethod"245jni_functions["CallVoidMethodV"] = not_implemented246jni_functions["CallVoidMethodA"] = "CallVoidMethodA"247#Calling Instance Methods of a Superclass248jni_functions["CallNonvirtualObjectMethod"] = "CallNonvirtualObjectMethod"249jni_functions["CallNonvirtualObjectMethodV"] = not_implemented250jni_functions["CallNonvirtualObjectMethodA"] = "CallNonvirtualObjectMethodA"251jni_functions["CallNonvirtualBooleanMethod"] = "CallNonvirtualBooleanMethod"252jni_functions["CallNonvirtualBooleanMethodV"] = not_implemented253jni_functions["CallNonvirtualBooleanMethodA"] = "CallNonvirtualBooleanMethodA"254jni_functions["CallNonvirtualByteMethod"] = "CallNonvirtualByteMethod"255jni_functions["CallNonvirtualByteMethodV"] = not_implemented256jni_functions["CallNonvirtualByteMethodA"] = "CallNonvirtualByteMethodA"257jni_functions["CallNonvirtualCharMethod"] = "CallNonvirtualCharMethod"258jni_functions["CallNonvirtualCharMethodV"] = not_implemented259jni_functions["CallNonvirtualCharMethodA"] = "CallNonvirtualCharMethodA"260jni_functions["CallNonvirtualShortMethod"] = "CallNonvirtualShortMethod"261jni_functions["CallNonvirtualShortMethodV"] = not_implemented262jni_functions["CallNonvirtualShortMethodA"] = "CallNonvirtualShortMethodA"263jni_functions["CallNonvirtualIntMethod"] = "CallNonvirtualIntMethod"264jni_functions["CallNonvirtualIntMethodV"] = not_implemented265jni_functions["CallNonvirtualIntMethodA"] = "CallNonvirtualIntMethodA"266jni_functions["CallNonvirtualLongMethod"] = "CallNonvirtualLongMethod"267jni_functions["CallNonvirtualLongMethodV"] = not_implemented268jni_functions["CallNonvirtualLongMethodA"] = "CallNonvirtualLongMethodA"269jni_functions["CallNonvirtualFloatMethod"] = not_implemented270jni_functions["CallNonvirtualFloatMethodV"] = not_implemented271jni_functions["CallNonvirtualFloatMethodA"] = not_implemented272jni_functions["CallNonvirtualDoubleMethod"] = not_implemented273jni_functions["CallNonvirtualDoubleMethodV"] = not_implemented274jni_functions["CallNonvirtualDoubleMethodA"] = not_implemented275jni_functions["CallNonvirtualVoidMethod"] = "CallNonvirtualVoidMethod"276jni_functions["CallNonvirtualVoidMethodV"] = not_implemented277jni_functions["CallNonvirtualVoidMethodA"] = "CallNonvirtualVoidMethodA"278# Instance Field Access279jni_functions["GetFieldID"] = "GetFieldID"280jni_functions["GetObjectField"] = "GetObjectField"281jni_functions["GetBooleanField"] = "GetBooleanField"282jni_functions["GetByteField"] = "GetByteField"283jni_functions["GetCharField"] = "GetCharField"284jni_functions["GetShortField"] = "GetShortField"285jni_functions["GetIntField"] = "GetIntField"286jni_functions["GetLongField"] = "GetLongField"287jni_functions["GetFloatField"] = not_implemented288jni_functions["GetDoubleField"] = not_implemented289jni_functions["SetObjectField"] = "SetField"290jni_functions["SetBooleanField"] = "SetField"291jni_functions["SetByteField"] = "SetField"292jni_functions["SetCharField"] = "SetField"293jni_functions["SetShortField"] = "SetField"294jni_functions["SetIntField"] = "SetField"295jni_functions["SetLongField"] = "SetField"296jni_functions["SetFloatField"] = not_implemented297jni_functions["SetDoubleField"] = not_implemented298# Static Method Calls299jni_functions["GetStaticMethodID"] = "GetMethodID"300jni_functions["CallStaticObjectMethod"] = "CallStaticObjectMethod"301jni_functions["CallStaticObjectMethodV"] = not_implemented302jni_functions["CallStaticObjectMethodA"] = "CallStaticObjectMethodA"303jni_functions["CallStaticBooleanMethod"] = "CallStaticBooleanMethod"304jni_functions["CallStaticBooleanMethodV"] = not_implemented305jni_functions["CallStaticBooleanMethodA"] = "CallStaticBooleanMethodA"306jni_functions["CallStaticByteMethod"] = "CallStaticByteMethod"307jni_functions["CallStaticByteMethodV"] = not_implemented308jni_functions["CallStaticByteMethodA"] = "CallStaticByteMethodA"309jni_functions["CallStaticCharMethod"] = "CallStaticCharMethod"310jni_functions["CallStaticCharMethodV"] = not_implemented311jni_functions["CallStaticCharMethodA"] = "CallStaticCharMethodA"312jni_functions["CallStaticShortMethod"] = "CallStaticShortMethod"313jni_functions["CallStaticShortMethodV"] = not_implemented314jni_functions["CallStaticShortMethodA"] = "CallStaticShortMethodA"315jni_functions["CallStaticIntMethod"] = "CallStaticIntMethod"316jni_functions["CallStaticIntMethodV"] = not_implemented317jni_functions["CallStaticIntMethodA"] = "CallStaticIntMethodA"318jni_functions["CallStaticLongMethod"] = "CallStaticLongMethod"319jni_functions["CallStaticLongMethodV"] = not_implemented320jni_functions["CallStaticLongMethodA"] = "CallStaticLongMethodA"321jni_functions["CallStaticFloatMethod"] = not_implemented322jni_functions["CallStaticFloatMethodV"] = not_implemented323jni_functions["CallStaticFloatMethodA"] = not_implemented324jni_functions["CallStaticDoubleMethod"] = not_implemented325jni_functions["CallStaticDoubleMethodV"] = not_implemented326jni_functions["CallStaticDoubleMethodA"] = not_implemented327jni_functions["CallStaticVoidMethod"] = "CallStaticVoidMethod"328jni_functions["CallStaticVoidMethodV"] = not_implemented329jni_functions["CallStaticVoidMethodA"] = "CallStaticVoidMethodA"330# Static Field Access331jni_functions["GetStaticFieldID"] = "GetFieldID"332jni_functions["GetStaticObjectField"] = "GetStaticObjectField"333jni_functions["GetStaticBooleanField"] = "GetStaticBooleanField"334jni_functions["GetStaticByteField"] = "GetStaticByteField"335jni_functions["GetStaticCharField"] = "GetStaticCharField"336jni_functions["GetStaticShortField"] = "GetStaticShortField"337jni_functions["GetStaticIntField"] = "GetStaticIntField"338jni_functions["GetStaticLongField"] = "GetStaticLongField"339jni_functions["GetStaticFloatField"] = not_implemented340jni_functions["GetStaticDoubleField"] = not_implemented341jni_functions["SetStaticObjectField"] = "SetStaticField"342jni_functions["SetStaticBooleanField"] = "SetStaticField"343jni_functions["SetStaticByteField"] = "SetStaticField"344jni_functions["SetStaticCharField"] = "SetStaticField"345jni_functions["SetStaticShortField"] = "SetStaticField"346jni_functions["SetStaticIntField"] = "SetStaticField"347jni_functions["SetStaticLongField"] = "SetStaticField"348jni_functions["SetStaticFloatField"] = not_implemented349jni_functions["SetStaticDoubleField"] = not_implemented350# String Operations351jni_functions["NewString"] = not_implemented352jni_functions["GetStringLength"] = not_implemented353jni_functions["GetStringChars"] = not_implemented354jni_functions["ReleaseStringChars"] = not_implemented355jni_functions["NewStringUTF"] = "NewStringUTF"356jni_functions["GetStringUTFLength"] = "GetStringUTFLength"357jni_functions["GetStringUTFChars"] = "GetStringUTFChars"358jni_functions["ReleaseStringUTFChars"] = "ReleaseStringUTFChars"359# Array Operations360jni_functions["GetArrayLength"] = "GetArrayLength"361jni_functions["NewObjectArray"] = "NewObjectArray"362jni_functions["GetObjectArrayElement"] = "GetObjectArrayElement"363jni_functions["SetObjectArrayElement"] = "SetObjectArrayElement"364jni_functions["NewBooleanArray"] = "NewBooleanArray"365jni_functions["NewByteArray"] = "NewByteArray"366jni_functions["NewCharArray"] = "NewCharArray"367jni_functions["NewShortArray"] = "NewShortArray"368jni_functions["NewIntArray"] = "NewIntArray"369jni_functions["NewLongArray"] = "NewLongArray"370jni_functions["NewFloatArray"] = not_implemented371jni_functions["NewDoubleArray"] = not_implemented372jni_functions["GetBooleanArrayElements"] = "GetArrayElements"373jni_functions["GetByteArrayElements"] = "GetArrayElements"374jni_functions["GetCharArrayElements"] = "GetArrayElements"375jni_functions["GetShortArrayElements"] = "GetArrayElements"376jni_functions["GetIntArrayElements"] = "GetArrayElements"377jni_functions["GetLongArrayElements"] = "GetArrayElements"378jni_functions["GetFloatArrayElements"] = not_implemented379jni_functions["GetDoubleArrayElements"] = not_implemented380jni_functions["ReleaseBooleanArrayElements"] = not_implemented381jni_functions["ReleaseByteArrayElements"] = "ReleaseArrayElements"382jni_functions["ReleaseCharArrayElements"] = "ReleaseArrayElements"383jni_functions["ReleaseShortArrayElements"] = "ReleaseArrayElements"384jni_functions["ReleaseIntArrayElements"] = "ReleaseArrayElements"385jni_functions["ReleaseLongArrayElements"] = "ReleaseArrayElements"386jni_functions["ReleaseFloatArrayElements"] = not_implemented387jni_functions["ReleaseDoubleArrayElements"] = not_implemented388jni_functions["GetBooleanArrayRegion"] = "GetArrayRegion"389jni_functions["GetByteArrayRegion"] = "GetArrayRegion"390jni_functions["GetCharArrayRegion"] = "GetArrayRegion"391jni_functions["GetShortArrayRegion"] = "GetArrayRegion"392jni_functions["GetIntArrayRegion"] = "GetArrayRegion"393jni_functions["GetLongArrayRegion"] = "GetArrayRegion"394jni_functions["GetFloatArrayRegion"] = not_implemented395jni_functions["GetDoubleArrayRegion"] = not_implemented396jni_functions["SetBooleanArrayRegion"] = "SetArrayRegion"397jni_functions["SetByteArrayRegion"] = "SetArrayRegion"398jni_functions["SetCharArrayRegion"] = "SetArrayRegion"399jni_functions["SetShortArrayRegion"] = "SetArrayRegion"400jni_functions["SetIntArrayRegion"] = "SetArrayRegion"401jni_functions["SetLongArrayRegion"] = "SetArrayRegion"402jni_functions["SetFloatArrayRegion"] = not_implemented403jni_functions["SetDoubleArrayRegion"] = not_implemented404# Native Method Registration405jni_functions["RegisterNatives"] = not_implemented406jni_functions["UnregisterNatives"] = not_implemented407# Monitor Operations408jni_functions["MonitorEnter"] = not_implemented409jni_functions["MonitorExit"] = not_implemented410# JavaVM Interface411jni_functions["GetJavaVM"] = not_implemented412# Misc413jni_functions["GetStringRegion"] = not_implemented414jni_functions["GetStringUTFRegion"] = not_implemented415jni_functions["GetPrimitiveArrayCritical"] = "GetArrayElements"416jni_functions["ReleasePrimitiveArrayCritical"] = "ReleaseArrayElements"417jni_functions["GetStringCritical"] = not_implemented418jni_functions["ReleaseStringCritical"] = not_implemented419jni_functions["NewWeakGlobalRef"] = "NewGlobalRef"420jni_functions["DeleteWeakGlobalRef"] = "DeleteGlobalRef"421jni_functions["ExceptionCheck"] = not_implemented422jni_functions["NewDirectByteBuffer"] = not_implemented423jni_functions["GetDirectBufferAddress"] = not_implemented424jni_functions["GetDirectBufferCapacity"] = not_implemented...
rpc.py
Source:rpc.py
...30 curry,31 excepts,32 partial,33)34def not_implemented(*args, **kwargs):35 raise NotImplementedError("RPC method not implemented")36@curry37def call_eth_tester(fn_name, eth_tester, fn_args, fn_kwargs=None):38 if fn_kwargs is None:39 fn_kwargs = {}40 return getattr(eth_tester, fn_name)(*fn_args, **fn_kwargs)41def without_eth_tester(fn):42 # workaround for: https://github.com/pytoolz/cytoolz/issues/10343 # @functools.wraps(fn)44 def inner(eth_tester, params):45 return fn(params)46 return inner47def without_params(fn):48 # workaround for: https://github.com/pytoolz/cytoolz/issues/103...
main.py
Source:main.py
...31from .middleware import (32 ethereum_tester_middleware,33 ethereum_tester_fixture_middleware,34)35def not_implemented(*args, **kwargs):36 raise NotImplementedError("RPC method not implemented")37@curry38def call_eth_tester(fn_name, eth_tester, fn_args, fn_kwargs=None):39 if fn_kwargs is None:40 fn_kwargs = {}41 return getattr(eth_tester, fn_name)(*fn_args, **fn_kwargs)42def without_eth_tester(fn):43 # workaround for: https://github.com/pytoolz/cytoolz/issues/10344 # @functools.wraps(fn)45 def inner(eth_tester, params):46 return fn(params)47 return inner48def without_params(fn):49 # workaround for: https://github.com/pytoolz/cytoolz/issues/103...
defaults.py
Source:defaults.py
...20 compose,21 curry,22 excepts,23)24def not_implemented(*args, **kwargs):25 raise NotImplementedError("RPC method not implemented")26@curry27def call_eth_tester(fn_name, eth_tester, fn_args, fn_kwargs=None):28 if fn_kwargs is None:29 fn_kwargs = {}30 return getattr(eth_tester, fn_name)(*fn_args, **fn_kwargs)31def without_eth_tester(fn):32 # workaround for: https://github.com/pytoolz/cytoolz/issues/10333 # @functools.wraps(fn)34 def inner(eth_tester, params):35 return fn(params)36 return inner37def without_params(fn):38 # workaround for: https://github.com/pytoolz/cytoolz/issues/103...
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.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!