How to use Ping method of telemetry Package

Best Keploy code snippet using telemetry.Ping

speedtest.go

Source:speedtest.go Github

copy

Full Screen

...26 defaultTelemetryServer = "https://librespeed.org"27 defaultTelemetryPath = "/results/telemetry.php"28 defaultTelemetryShare = "/results/"29)30type PingJob struct {31 Index int32 Server defs.Server33}34type PingResult struct {35 Index int36 Ping float6437}38// SpeedTest is the actual main function that handles the speed test(s)39func SpeedTest(c *cli.Context) error {40 // check for suppressed output flags41 var silent bool42 if c.Bool(defs.OptionSimple) || c.Bool(defs.OptionJSON) || c.Bool(defs.OptionCSV) {43 log.SetLevel(log.WarnLevel)44 silent = true45 }46 // check for debug flag47 if c.Bool(defs.OptionDebug) {48 log.SetLevel(log.DebugLevel)49 }50 // print help51 if c.Bool(defs.OptionHelp) {52 return cli.ShowAppHelp(c)53 }54 // print version55 if c.Bool(defs.OptionVersion) {56 log.Warnf("%s %s (built on %s)", defs.ProgName, defs.ProgVersion, defs.BuildDate)57 log.Warn("https://github.com/librespeed/speedtest-cli")58 log.Warn("Licensed under GNU Lesser General Public License v3.0")59 log.Warn("LibreSpeed\tCopyright (C) 2016-2020 Federico Dossena")60 log.Warn("librespeed-cli\tCopyright (C) 2020 Maddie Zhan")61 log.Warn("librespeed.org\tCopyright (C)")62 return nil63 }64 // set CSV delimiter65 gocsv.TagSeparator = c.String(defs.OptionCSVDelimiter)66 // if --csv-header is given, print the header and exit (same behavior speedtest-cli)67 if c.Bool(defs.OptionCSVHeader) {68 var rep []report.CSVReport69 b, _ := gocsv.MarshalBytes(&rep)70 log.Warnf("%s", b)71 return nil72 }73 // read telemetry settings if --share or any --telemetry option is given74 var telemetryServer defs.TelemetryServer75 telemetryJSON := c.String(defs.OptionTelemetryJSON)76 telemetryLevel := c.String(defs.OptionTelemetryLevel)77 telemetryServerString := c.String(defs.OptionTelemetryServer)78 telemetryPath := c.String(defs.OptionTelemetryPath)79 telemetryShare := c.String(defs.OptionTelemetryShare)80 if c.Bool(defs.OptionShare) || telemetryJSON != "" || telemetryLevel != "" || telemetryServerString != "" || telemetryPath != "" || telemetryShare != "" {81 if telemetryJSON != "" {82 b, err := ioutil.ReadFile(telemetryJSON)83 if err != nil {84 log.Errorf("Cannot read %s: %s", telemetryJSON, err)85 return err86 }87 if err := json.Unmarshal(b, &telemetryServer); err != nil {88 log.Errorf("Error parsing %s: %s", err)89 return err90 }91 }92 if telemetryLevel != "" {93 if telemetryLevel != "disabled" && telemetryLevel != "basic" && telemetryLevel != "full" && telemetryLevel != "debug" {94 log.Fatalf("Unsupported telemetry level: %s", telemetryLevel)95 }96 telemetryServer.Level = telemetryLevel97 } else if telemetryServer.Level == "" {98 telemetryServer.Level = defaultTelemetryLevel99 }100 if telemetryServerString != "" {101 telemetryServer.Server = telemetryServerString102 } else if telemetryServer.Server == "" {103 telemetryServer.Server = defaultTelemetryServer104 }105 if telemetryPath != "" {106 telemetryServer.Path = telemetryPath107 } else if telemetryServer.Path == "" {108 telemetryServer.Path = defaultTelemetryPath109 }110 if telemetryShare != "" {111 telemetryServer.Share = telemetryShare112 } else if telemetryServer.Share == "" {113 telemetryServer.Share = defaultTelemetryShare114 }115 }116 if req := c.Int(defs.OptionConcurrent); req <= 0 {117 log.Errorf("Concurrent requests cannot be lower than 1: %d is given", req)118 return errors.New("invalid concurrent requests setting")119 }120 // HTTP requests timeout121 http.DefaultClient.Timeout = time.Duration(c.Int(defs.OptionTimeout)) * time.Second122 forceIPv4 := c.Bool(defs.OptionIPv4)123 forceIPv6 := c.Bool(defs.OptionIPv6)124 var network string125 switch {126 case forceIPv4:127 network = "ip4"128 case forceIPv6:129 network = "ip6"130 default:131 network = "ip"132 }133 transport := http.DefaultTransport.(*http.Transport).Clone()134 transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: c.Bool(defs.OptionSkipCertVerify)}135 // bind to source IP address if given, or if ipv4/ipv6 is forced136 if src := c.String(defs.OptionSource); src != "" || (forceIPv4 || forceIPv6) {137 var localTCPAddr *net.TCPAddr138 if src != "" {139 // first we parse the IP to see if it's valid140 addr, err := net.ResolveIPAddr(network, src)141 if err != nil {142 if strings.Contains(err.Error(), "no suitable address") {143 if forceIPv6 {144 log.Errorf("Address %s is not a valid IPv6 address", src)145 } else {146 log.Errorf("Address %s is not a valid IPv4 address", src)147 }148 } else {149 log.Errorf("Error parsing source IP: %s", err)150 }151 return err152 }153 log.Debugf("Using %s as source IP", src)154 localTCPAddr = &net.TCPAddr{IP: addr.IP}155 }156 var dialContext func(context.Context, string, string) (net.Conn, error)157 defaultDialer := &net.Dialer{158 Timeout: 30 * time.Second,159 KeepAlive: 30 * time.Second,160 }161 if localTCPAddr != nil {162 defaultDialer.LocalAddr = localTCPAddr163 }164 switch {165 case forceIPv4:166 dialContext = func(ctx context.Context, network, address string) (conn net.Conn, err error) {167 return defaultDialer.DialContext(ctx, "tcp4", address)168 }169 case forceIPv6:170 dialContext = func(ctx context.Context, network, address string) (conn net.Conn, err error) {171 return defaultDialer.DialContext(ctx, "tcp6", address)172 }173 default:174 dialContext = defaultDialer.DialContext175 }176 // set default HTTP client's Transport to the one that binds the source address177 // this is modified from http.DefaultTransport178 transport.DialContext = dialContext179 }180 http.DefaultClient.Transport = transport181 // load server list182 var servers []defs.Server183 var err error184 if str := c.String(defs.OptionLocalJSON); str != "" {185 switch str {186 case "-":187 // load server list from stdin188 log.Info("Using local JSON server list from stdin")189 servers, err = getLocalServersReader(c.Bool(defs.OptionSecure), os.Stdin, c.IntSlice(defs.OptionExclude), c.IntSlice(defs.OptionServer), !c.Bool(defs.OptionList))190 default:191 // load server list from local JSON file192 log.Infof("Using local JSON server list: %s", str)193 servers, err = getLocalServers(c.Bool(defs.OptionSecure), str, c.IntSlice(defs.OptionExclude), c.IntSlice(defs.OptionServer), !c.Bool(defs.OptionList))194 }195 } else {196 // fetch the server list JSON and parse it into the `servers` array197 serverUrl := serverListUrl198 if str := c.String(defs.OptionServerJSON); str != "" {199 serverUrl = str200 }201 log.Infof("Retrieving server list from %s", serverUrl)202 servers, err = getServerList(c.Bool(defs.OptionSecure), serverUrl, c.IntSlice(defs.OptionExclude), c.IntSlice(defs.OptionServer), !c.Bool(defs.OptionList))203 if err != nil {204 log.Info("Retry with /.well-known/librespeed")205 servers, err = getServerList(c.Bool(defs.OptionSecure), serverUrl+"/.well-known/librespeed", c.IntSlice(defs.OptionExclude), c.IntSlice(defs.OptionServer), !c.Bool(defs.OptionList))206 }207 }208 if err != nil {209 log.Errorf("Error when fetching server list: %s", err)210 return err211 }212 // if --list is given, list all the servers fetched and exit213 if c.Bool(defs.OptionList) {214 for _, svr := range servers {215 var sponsorMsg string216 if svr.Sponsor() != "" {217 sponsorMsg = fmt.Sprintf(" [Sponsor: %s]", svr.Sponsor())218 }219 log.Warnf("%d: %s (%s) %s", svr.ID, svr.Name, svr.Server, sponsorMsg)220 }221 return nil222 }223 // if --server is given, do speed tests with all of them224 if len(c.IntSlice(defs.OptionServer)) > 0 {225 return doSpeedTest(c, servers, telemetryServer, network, silent)226 } else {227 // else select the fastest server from the list228 log.Info("Selecting the fastest server based on ping")229 var wg sync.WaitGroup230 jobs := make(chan PingJob, len(servers))231 results := make(chan PingResult, len(servers))232 done := make(chan struct{})233 pingList := make(map[int]float64)234 // spawn 10 concurrent pingers235 for i := 0; i < 10; i++ {236 go pingWorker(jobs, results, &wg, c.String(defs.OptionSource), network, c.Bool(defs.OptionNoICMP))237 }238 // send ping jobs to workers239 for idx, server := range servers {240 wg.Add(1)241 jobs <- PingJob{Index: idx, Server: server}242 }243 go func() {244 wg.Wait()245 close(done)246 }()247 Loop:248 for {249 select {250 case result := <-results:251 pingList[result.Index] = result.Ping252 case <-done:253 break Loop254 }255 }256 if len(pingList) == 0 {257 log.Fatal("No server is currently available, please try again later.")258 }259 // get the fastest server's index in the `servers` array260 var serverIdx int261 for idx, ping := range pingList {262 if ping > 0 && ping <= pingList[serverIdx] {263 serverIdx = idx264 }265 }266 // do speed test on the server267 return doSpeedTest(c, []defs.Server{servers[serverIdx]}, telemetryServer, network, silent)268 }269}270func pingWorker(jobs <-chan PingJob, results chan<- PingResult, wg *sync.WaitGroup, srcIp, network string, noICMP bool) {271 for {272 job := <-jobs273 server := job.Server274 // get the URL of the speed test server from the JSON275 u, err := server.GetURL()276 if err != nil {277 log.Debugf("Server URL is invalid for %s (%s), skipping", server.Name, server.Server)278 wg.Done()279 return280 }281 // check the server is up by accessing the ping URL and checking its returned value == empty and status code == 200282 if server.IsUp() {283 // skip ICMP if option given284 server.NoICMP = noICMP285 // if server is up, get ping286 ping, _, err := server.ICMPPingAndJitter(1, srcIp, network)287 if err != nil {288 log.Debugf("Can't ping server %s (%s), skipping", server.Name, u.Hostname())289 wg.Done()290 return291 }292 // return result293 results <- PingResult{Index: job.Index, Ping: ping}294 wg.Done()295 } else {296 log.Debugf("Server %s (%s) doesn't seem to be up, skipping", server.Name, u.Hostname())297 wg.Done()298 }299 }300}301// getServerList fetches the server JSON from a remote server302func getServerList(forceHTTPS bool, serverList string, excludes, specific []int, filter bool) ([]defs.Server, error) {303 // --exclude and --server cannot be used at the same time304 if len(excludes) > 0 && len(specific) > 0 {305 return nil, errors.New("either --exclude or --server can be used")306 }307 // getting the server list from remote...

Full Screen

Full Screen

watcher.go

Source:watcher.go Github

copy

Full Screen

...18 oldestOutput uint3219}20// Config набор настроек для Watcher21type Config struct {22 // PingsToStop количество неудачных ping запросов,23 // после которых рантайм признается отказавшим.24 PingsToStop int `yaml:"pings-to-stop"`25 // PingFrequency время между запросами к рантаймам для получения состояния.26 PingFrequency util.Duration `yaml:"ping-freq"`27}28// NewConfig создает новый Config с настройками по-умолчанию.29func NewConfig() *Config {30 return &Config{31 PingsToStop: 3,32 PingFrequency: util.Duration(5 * time.Second),33 }34}35// Watcher структура для контроля запущенных действий.36type Watcher struct {37 runtimesMutex sync.RWMutex38 runtimes map[string]*workingRuntime39 cfg *Config40 logger *util.Logger41}42// NewWatcher создает новый объект watcher43func newWatcher(l *util.Logger, cfg *Config) *Watcher {44 return &Watcher{45 runtimes: make(map[string]*workingRuntime),46 cfg: cfg,47 logger: l.WithName("watcher"),48 }49}50// StartRuntime запускает регистрирует действие для наблюдения51func (w *Watcher) StartRuntime(ctx context.Context, r *Runtime) error {52 w.runtimesMutex.Lock()53 defer w.runtimesMutex.Unlock()54 if err := r.Start(ctx); err != nil {55 return err56 }57 runtimeName := r.Name()58 if _, ok := w.runtimes[runtimeName]; ok {59 return ErrRuntimeAlreadyRegistered60 }61 w.runtimes[runtimeName] = &workingRuntime{62 runtime: r,63 pingsFailed: 0,64 }65 w.logger.Infof("runtime '%s' started", runtimeName)66 return nil67}68// StopRuntime остановка действия.69func (w *Watcher) StopRuntime(schemeName, actionName string) error {70 w.runtimesMutex.Lock()71 defer w.runtimesMutex.Unlock()72 runtimeName := buildRuntimeName(schemeName, actionName)73 runtime, ok := w.runtimes[runtimeName]74 if !ok {75 return ErrUnknownRuntime76 }77 delete(w.runtimes, runtimeName)78 if err := runtime.runtime.Stop(); err != nil {79 return err80 }81 w.logger.Infof("runtime '%s' stopped", runtimeName)82 return nil83}84// ChangeOutRuntime изменяет один из выходных потоков рантайма.85func (w *Watcher) ChangeOutRuntime(schemeName, actionName, oldOut, newOut string) error {86 w.runtimesMutex.Lock()87 defer w.runtimesMutex.Unlock()88 runtimeName := buildRuntimeName(schemeName, actionName)89 runtime, ok := w.runtimes[runtimeName]90 if !ok {91 return ErrUnknownRuntime92 }93 if err := runtime.runtime.ChangeOut(oldOut, newOut); err != nil {94 return err95 }96 w.logger.Infof("runtime '%s' changed out %s -> %s", runtimeName, oldOut, newOut)97 return nil98}99// GetRuntimesTelemetry возвращает информацию о состояниях действий.100func (w *Watcher) GetRuntimesTelemetry() []*message.RuntimeTelemetry {101 w.runtimesMutex.Lock()102 defer w.runtimesMutex.Unlock()103 runtimes := make([]*message.RuntimeTelemetry, 0, len(w.runtimes))104 for _, runtime := range w.runtimes {105 status := message.RuntimeStatusOK106 if runtime.pingsFailed > 0 {107 status = message.RuntimeStatusPending108 }109 telemetry := &message.RuntimeTelemetry{110 SchemeName: runtime.runtime.SchemeName(),111 ActionName: runtime.runtime.ActionName(),112 Status: status,113 OldestOutput: runtime.oldestOutput,114 }115 runtimes = append(runtimes, telemetry)116 }117 // Здесь Debugf, так как этот метод вызывается на каждый ping от meta_node.118 w.logger.Debugf("telemetry for %d runtimes loaded", len(runtimes))119 return runtimes120}121// Start запускает Watcher в работу и выходит122func (w *Watcher) run(ctx context.Context) {123 w.logger.Info("watcher started")124 defer w.logger.Info("watcher stopped")125 ticker := time.NewTicker(time.Duration(w.cfg.PingFrequency))126 for {127 select {128 case <-ctx.Done():129 return130 case <-ticker.C:131 w.pingRuntimes()132 }133 }134}135func (w *Watcher) pingRuntimes() {136 defer w.logger.Debugf("ping runtimes done")137 w.runtimesMutex.RLock()138 defer w.runtimesMutex.RUnlock()139 for runtimeName, runtime := range w.runtimes {140 telemetry, err := runtime.runtime.Ping()141 if err != nil {142 runtime.pingsFailed++143 w.logger.Warnf("ping for runtime '%s' failed: %v", runtimeName, err)144 if runtime.pingsFailed >= w.cfg.PingsToStop {145 w.logger.Warnf("runtime '%s' %d pings failed: stopping runtime", runtimeName, runtime.pingsFailed)146 delete(w.runtimes, runtimeName)147 if err := runtime.runtime.Stop(); err != nil {148 w.logger.Errorf("runtime '%s' stop failed: skipping runtime: %v", runtimeName, err)149 }150 w.logger.Warnf("runtime '%s' stopped", runtimeName)151 }152 continue153 }154 runtime.oldestOutput = telemetry.OldestOutput155 runtime.pingsFailed = 0156 }157}...

Full Screen

Full Screen

ping.go

Source:ping.go Github

copy

Full Screen

...9 "github.com/libp2p/go-libp2p-core/peer"10 "github.com/libp2p/go-libp2p/p2p/protocol/ping"11)12var _ telemetry.Collector = (*pingCollector)(nil)13type PingOptions struct {14 PingCount int15 Timeout time.Duration16}17type pingCollector struct {18 opts PingOptions19 h host.Host20 picker *peerPicker21}22func Ping(h host.Host, opts PingOptions) telemetry.Collector {23 return &pingCollector{24 opts: opts,25 h: h,26 picker: newPeerPicker(h),27 }28}29// Name implements telemetry.Collector30func (*pingCollector) Name() string {31 return "Ping"32}33// Close implements Collector34func (c *pingCollector) Close() {35 c.picker.close()36}37// Collect implements Collector38func (c *pingCollector) Collect(ctx context.Context, stream *telemetry.Stream) error {39 if p, ok := c.picker.pick(); ok {40 ps, err := c.ping(ctx, p)41 if err != nil {42 return err43 }44 return datapoint.PingSerialize(ps, stream)45 }46 return nil47}48func (c *pingCollector) ping(ctx context.Context, p peer.ID) (*datapoint.Ping, error) {49 ctx, cancel := context.WithTimeout(ctx, c.opts.Timeout)50 defer cancel()51 if c.h.Network().Connectedness(p) != network.Connected {52 if err := c.h.Connect(ctx, c.h.Peerstore().PeerInfo(p)); err != nil {53 return nil, err54 }55 }56 durations := make([]time.Duration, c.opts.PingCount)57 counter := 058 cresult := ping.Ping(network.WithNoDial(ctx, "ping"), c.h, p)59 for result := range cresult {60 if result.Error != nil {61 return nil, result.Error62 }63 durations[counter] = result.RTT64 counter += 165 if counter == c.opts.PingCount {66 break67 }68 }69 source := peer.AddrInfo{70 ID: c.h.ID(),71 Addrs: c.h.Addrs(),72 }73 destination := c.h.Peerstore().PeerInfo(p)74 return &datapoint.Ping{75 Timestamp: datapoint.NewTimestamp(),76 Source: source,77 Destination: destination,78 Durations: durations,79 }, nil80}...

Full Screen

Full Screen

Ping

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 t := telemetry.New()4 t.Connect()5 t.Ping(1 * time.Second)6 fmt.Println("Time taken to ping is: ", monotime.Since(t.GetLastPingTime()))7}8import (9func main() {10 t := telemetry.New()11 t.Connect()12 t.Send()13 fmt.Println("Time taken to send is: ", monotime.Since(t.GetLastSendTime()))14}15import (16func main() {17 t := telemetry.New()18 t.Connect()19 t.Send()20 fmt.Println("Time taken to send is: ", monotime.Since(t.GetLastSendTime()))21}22import (23func main() {24 t := telemetry.New()25 t.Connect()26 t.Ping(1 * time.Second)27 fmt.Println("Time taken to ping is: ", monotime.Since(t.GetLastPingTime()))28}29import (30func main() {31 t := telemetry.New()32 t.Connect()33 t.Ping(1 * time.Second)34 fmt.Println("Time taken to ping is: ", monotime.Since(t.GetLastPingTime()))35}36import (

Full Screen

Full Screen

Ping

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 node, _ := goeapi.ConnectTo("veos01")4 telemetry, _ := node.Telemetry()5 ping, _ := telemetry.Ping("veos01")6 fmt.Println(ping)7}8import (9func main() {10 node, _ := goeapi.ConnectTo("veos01")11 telemetry, _ := node.Telemetry()12 result, _ := telemetry.Get()13 fmt.Println(result)14}15import (16func main() {17 node, _ := goeapi.ConnectTo("veos01")18 telemetry, _ := node.Telemetry()19 result, _ := telemetry.Get()20 fmt.Println(result["cpuUtilization"])21}

Full Screen

Full Screen

Ping

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 node, _ := goeapi.ConnectTo("veos01")4 telemetry := node.Telemetry()5 ping := telemetry.NewPing()6 ping.SetDestination("

Full Screen

Full Screen

Ping

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 t := telemetry.NewTelemetry()4 ch := make(chan *telemetry.TelemetryData)5 errCh := make(chan error)6 t.AddSubscription("show interface", "all-interfaces", ch, errCh)7 t.Start()8 for {9 select {10 fmt.Println(data)11 fmt.Println(err)12 case <-time.After(5 * time.Second):13 }14 }15}16import (17func main() {18 t := telemetry.NewTelemetry()19 ch := make(chan *telemetry.TelemetryData)20 errCh := make(chan error)21 t.Subscribe("show interface", "all-interfaces", ch, errCh)22 for {23 select {24 fmt.Println(data)25 fmt.Println(err)26 case <-time.After(5 * time.Second):27 }28 }29}30import (31func main() {32 t := telemetry.NewTelemetry()33 ch := make(chan *telemetry.TelemetryData)34 errCh := make(chan error)35 t.Subscribe("show interface", "all-interfaces", ch

Full Screen

Full Screen

Ping

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 node, _ := goeapi.ConnectTo("veos01")4 resp, _ := node.Enable(cmd)5 fmt.Println(resp)6}7import (8func main() {9 node, _ := goeapi.ConnectTo("veos01")10 cmd := []string{"show version", "show clock"}11 resp, _ := node.Enable(cmd)12 fmt.Println(resp)13}14import (15func main() {16 node, _ := goeapi.ConnectTo("veos01")17 cmd := []string{"show version", "show clock"}18 resp, _ := node.Enable(cmd)19 fmt.Println(resp[0])20 fmt.Println(resp[1])21}22import (23func main() {24 node, _ := goeapi.ConnectTo("veos01")25 cmd := []string{"show version", "show clock"}26 resp, _ := node.Enable(cmd)27 fmt.Println(resp[0].Result)28 fmt.Println(resp[1].Result)29}30import (31func main() {32 node, _ := goeapi.ConnectTo("veos01")

Full Screen

Full Screen

Ping

Using AI Code Generation

copy

Full Screen

1import "github.com/aristanetworks/goarista/telemetry"2import "fmt"3func main() {4 t := telemetry.NewTelemetry()5 err := t.Ping()6 if err == nil {7 fmt.Println("Ping successful")8 } else {9 fmt.Println("Ping failed")10 }11}12import "github.com/aristanetworks/goarista/telemetry"13import "fmt"14func main() {15 t := telemetry.NewTelemetry()16 sub := telemetry.NewSubscription()17 sub.SetPath("/interfaces/interface/state/counters")18 t.AddSubscription(sub)19 err := t.Subscribe()20 if err == nil {21 fmt.Println("Subscribe successful")22 } else {23 fmt.Println("Subscribe failed")24 }25}26import "github.com/aristanetworks/goarista/telemetry"27import "fmt"28func main() {29 t := telemetry.NewTelemetry()30 sub := telemetry.NewSubscription()31 sub.SetPath("/interfaces/interface/state/counters")32 t.AddSubscription(sub)33 err := t.Unsubscribe()34 if err == nil {35 fmt.Println("Unsubscribe successful")36 } else {37 fmt.Println("Unsubscribe failed")38 }39}40import "github.com/aristanetworks/goarista/telemetry"41import "fmt"42func main() {43 t := telemetry.NewTelemetry()44 err := t.SetGnmiTarget("localhost:6030")45 if err == nil {46 fmt.Println("SetGnmiTarget successful")47 } else {48 fmt.Println("SetGnmi

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 Keploy 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