How to use parseIP method of vmm Package

Best Syzkaller code snippet using vmm.parseIP

nodes_test.go

Source:nodes_test.go Github

copy

Full Screen

1// Copyright 2017 Cisco Systems, Inc.2//3// Licensed under the Apache License, Version 2.0 (the "License");4// you may not use this file except in compliance with the License.5// You may obtain a copy of the License at6//7// http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// distributed under the License is distributed on an "AS IS" BASIS,11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12// See the License for the specific language governing permissions and13// limitations under the License.14package controller15import (16 "encoding/json"17 "fmt"18 "net"19 "testing"20 "time"21 v1 "k8s.io/api/core/v1"22 "github.com/noironetworks/aci-containers/pkg/ipam"23 "github.com/noironetworks/aci-containers/pkg/metadata"24 "github.com/noironetworks/aci-containers/pkg/apicapi"25 tu "github.com/noironetworks/aci-containers/pkg/testutil"26 //"github.com/stretchr/testify/assert"27)28func waitForSEpAnnot(t *testing.T, cont *testAciController,29 ipv4 net.IP, ipv6 net.IP, mac *string, desc string) {30 tu.WaitFor(t, desc, 500*time.Millisecond,31 func(last bool) (bool, error) {32 if !tu.WaitCondition(t, last, func() bool {33 return len(cont.nodeUpdates) >= 134 }, desc, "update") {35 return false, nil36 }37 annot := cont.nodeUpdates[len(cont.nodeUpdates)-1].38 ObjectMeta.Annotations[metadata.ServiceEpAnnotation]39 ep := &metadata.ServiceEndpoint{}40 err := json.Unmarshal([]byte(annot), ep)41 if !tu.WaitNil(t, last, err, desc, "unmarshal", err) {42 return false, nil43 }44 _, err = net.ParseMAC(ep.Mac)45 return tu.WaitNil(t, last, err, desc, "hardware addr parse", err) &&46 (mac == nil ||47 tu.WaitEqual(t, last, *mac, ep.Mac, desc, "mac")) &&48 tu.WaitEqual(t, last, ipv4, ep.Ipv4, desc, "ipv4") &&49 tu.WaitEqual(t, last, ipv6, ep.Ipv6, desc, "ipv6"), nil50 })51}52var odevMac = "aa:bb:cc:dd:ee:ff"53func setupODev(cont *testAciController, nodeName string, hasMac bool) {54 oDev := apicapi.EmptyApicObject("opflexODev", nodeName)55 oDev.SetAttr("hostName", nodeName)56 if hasMac {57 oDev.SetAttr("mac", odevMac)58 }59 oDev.SetAttr("fabricPathDn",60 "topology/pod-1/paths-301/pathep-[eth1/33]")61 oDev.SetAttr("devType", "k8s")62 oDev.SetAttr("domName", "kube")63 oDev.SetAttr("ctrlrName", "kube")64 cont.opflexDeviceChanged(oDev)65}66func TestServiceEpAnnotationV4(t *testing.T) {67 cont := testController()68 cont.config.AciVmmDomain = "kube"69 cont.config.AciVmmController = "kube"70 cont.config.NodeServiceIpPool = []ipam.IpRange{71 {Start: net.ParseIP("10.1.1.2"), End: net.ParseIP("10.1.1.3")},72 }73 cont.AciController.initIpam()74 cont.run()75 setupODev(cont, "node1", true)76 setupODev(cont, "node2", true)77 setupODev(cont, "node3", false)78 cont.fakeNodeSource.Add(node("node1"))79 waitForSEpAnnot(t, cont, net.ParseIP("10.1.1.2"), nil, &odevMac, "simple")80 cont.nodeUpdates = nil81 cont.fakeNodeSource.Add(node("node2"))82 waitForSEpAnnot(t, cont, net.ParseIP("10.1.1.3"), nil, &odevMac, "second")83 cont.nodeUpdates = nil84 cont.fakeNodeSource.Add(node("node3"))85 waitForSEpAnnot(t, cont, nil, nil, nil, "noneleft")86 cont.nodeUpdates = nil87 setupODev(cont, "node3", true)88 waitForSEpAnnot(t, cont, nil, nil, &odevMac, "odev update add mac")89 cont.stop()90}91func TestServiceEpAnnotationV6(t *testing.T) {92 cont := testController()93 cont.config.AciVmmDomain = "kube"94 cont.config.AciVmmController = "kube"95 cont.config.NodeServiceIpPool = []ipam.IpRange{96 {Start: net.ParseIP("fd43:85d7:bcf2:9ad2::2"), End: net.ParseIP("fd43:85d7:bcf2:9ad2::3")},97 }98 cont.AciController.initIpam()99 cont.run()100 setupODev(cont, "node1", false)101 setupODev(cont, "node2", true)102 setupODev(cont, "node3", true)103 cont.fakeNodeSource.Add(node("node1"))104 waitForSEpAnnot(t, cont, nil, net.ParseIP("fd43:85d7:bcf2:9ad2::2"),105 nil, "simple")106 cont.nodeUpdates = nil107 cont.fakeNodeSource.Add(node("node2"))108 waitForSEpAnnot(t, cont, nil, net.ParseIP("fd43:85d7:bcf2:9ad2::3"),109 &odevMac, "second")110 cont.nodeUpdates = nil111 cont.fakeNodeSource.Add(node("node3"))112 waitForSEpAnnot(t, cont, nil, nil, &odevMac, "noneleft")113 cont.stop()114}115func TestServiceEpAnnotationExisting(t *testing.T) {116 cont := testController()117 cont.config.AciVmmDomain = "kube"118 cont.config.AciVmmController = "kube"119 cont.config.NodeServiceIpPool = []ipam.IpRange{120 {Start: net.ParseIP("10.1.1.2"), End: net.ParseIP("10.1.1.4")},121 {Start: net.ParseIP("fd43:85d7:bcf2:9ad2::2"), End: net.ParseIP("fd43:85d7:bcf2:9ad2::4")},122 }123 cont.AciController.initIpam()124 cont.run()125 setupODev(cont, "node1", false)126 setupODev(cont, "node2", true)127 setupODev(cont, "node3", false)128 ep := &metadata.ServiceEndpoint{129 Ipv4: net.ParseIP("10.1.1.1"),130 Ipv6: net.ParseIP("fd43:85d7:bcf2:9ad2::1"),131 }132 n := node("node1")133 raw, _ := json.Marshal(ep)134 n.ObjectMeta.Annotations[metadata.ServiceEpAnnotation] = string(raw)135 cont.fakeNodeSource.Add(n)136 waitForSEpAnnot(t, cont, net.ParseIP("10.1.1.2"),137 net.ParseIP("fd43:85d7:bcf2:9ad2::2"), nil, "out of range")138 cont.nodeUpdates = nil139 n = node("node2")140 ep.Mac = "00:0c:29:92:fe:d0"141 ep.Ipv4 = net.ParseIP("10.1.1.4")142 raw, _ = json.Marshal(ep)143 n.ObjectMeta.Annotations[metadata.ServiceEpAnnotation] = string(raw)144 cont.fakeNodeSource.Add(n)145 waitForSEpAnnot(t, cont, net.ParseIP("10.1.1.4"),146 net.ParseIP("fd43:85d7:bcf2:9ad2::3"), &odevMac, "in range")147 cont.nodeUpdates = nil148 n = node("node3")149 ep.Mac = "00:0c:29:92:fe:d0"150 ep.Ipv4 = net.ParseIP("10.1.1.5")151 raw, _ = json.Marshal(ep)152 n.ObjectMeta.Annotations[metadata.ServiceEpAnnotation] = string(raw)153 cont.fakeNodeSource.Add(n)154 waitForSEpAnnot(t, cont, net.ParseIP("10.1.1.3"),155 net.ParseIP("fd43:85d7:bcf2:9ad2::4"), &ep.Mac, "out of range no odev")156 cont.stop()157}158func waitForPodNetAnnot(t *testing.T, cont *testAciController,159 expIps *metadata.NetIps, desc string) {160 tu.WaitFor(t, desc, 500*time.Millisecond,161 func(last bool) (bool, error) {162 if !tu.WaitCondition(t, last, func() bool {163 return len(cont.nodeUpdates) >= 1164 }, desc, "update") {165 return false, nil166 }167 annot := cont.nodeUpdates[len(cont.nodeUpdates)-1].168 ObjectMeta.Annotations[metadata.PodNetworkRangeAnnotation]169 ips := &metadata.NetIps{}170 err := json.Unmarshal([]byte(annot), ips)171 if !tu.WaitNil(t, last, err, desc, "unmarshal", err) {172 return false, nil173 }174 return tu.WaitEqual(t, last, expIps, ips, desc), nil175 })176}177func TestPodNetV6Annotation(t *testing.T) {178 cont := testController()179 cont.config.PodIpPoolChunkSize = 2180 cont.config.PodIpPool = []ipam.IpRange{181 {Start: net.ParseIP("1:1:1:1::2"), End: net.ParseIP("1:1:1:1::12")},182 }183 cont.AciController.initIpam()184 cont.run()185 {186 cont.nodeUpdates = nil187 cont.fakeNodeSource.Add(node("node1"))188 waitForPodNetAnnot(t, cont, &metadata.NetIps{189 V6: []ipam.IpRange{190 {Start: net.ParseIP("1:1:1:1::2"), End: net.ParseIP("1:1:1:1::3")},191 },192 }, "simple")193 }194 cont.stop()195}196func TestPodNetAnnotation(t *testing.T) {197 cont := testController()198 cont.config.AciVmmDomain = "kube"199 cont.config.AciVmmController = "kube"200 cont.config.PodIpPoolChunkSize = 2201 cont.config.PodIpPool = []ipam.IpRange{202 {Start: net.ParseIP("10.1.1.2"), End: net.ParseIP("10.1.1.13")},203 }204 cont.AciController.initIpam()205 cont.run()206 setupODev(cont, "node2", true)207 {208 cont.nodeUpdates = nil209 cont.fakeNodeSource.Add(node("node1"))210 waitForPodNetAnnot(t, cont, &metadata.NetIps{211 V4: []ipam.IpRange{212 {Start: net.ParseIP("10.1.1.2"), End: net.ParseIP("10.1.1.3")},213 },214 }, "simple")215 }216 {217 cont.nodeUpdates = nil218 cont.fakePodSource.Add(podOnNode("testns", "testpod", "node1"))219 cont.fakePodSource.Add(podOnNode("testns", "testpod2", "node1"))220 waitForPodNetAnnot(t, cont, &metadata.NetIps{221 V4: []ipam.IpRange{222 {Start: net.ParseIP("10.1.1.2"), End: net.ParseIP("10.1.1.5")},223 },224 }, "newchunk")225 }226 {227 cont.nodeUpdates = nil228 node2 := node("node2")229 ips := &metadata.NetIps{230 V4: []ipam.IpRange{231 {Start: net.ParseIP("10.1.1.7"), End: net.ParseIP("10.1.1.9")},232 },233 }234 raw, _ := json.Marshal(ips)235 node2.ObjectMeta.Annotations[metadata.PodNetworkRangeAnnotation] = string(raw)236 cont.fakeNodeSource.Add(node2)237 waitForPodNetAnnot(t, cont, ips, "existing")238 }239 {240 cont.nodeUpdates = nil241 node3 := node("node3")242 ips := &metadata.NetIps{243 V4: []ipam.IpRange{244 {Start: net.ParseIP("10.1.1.10"), End: net.ParseIP("10.1.1.15")},245 },246 }247 raw, _ := json.Marshal(ips)248 node3.ObjectMeta.Annotations[metadata.PodNetworkRangeAnnotation] = string(raw)249 cont.fakeNodeSource.Add(node3)250 waitForPodNetAnnot(t, cont, &metadata.NetIps{251 V4: []ipam.IpRange{252 {Start: net.ParseIP("10.1.1.10"), End: net.ParseIP("10.1.1.13")},253 },254 }, "out of range intersection")255 }256 cont.stop()257}258func TestNodeNetPol(t *testing.T) {259 cont := testController()260 cont.config.AciPolicyTenant = "test-tenant"261 node := node("node1")262 node.Status.Addresses = []v1.NodeAddress{263 {Type: "Hostname", Address: "test-node"},264 {Type: "InternalIP", Address: "1.1.1.1"},265 }266 cont.fakeNodeSource.Add(node)267 cont.run()268 key := cont.aciNameForKey("node", "node1")269 sg := apicNodeNetPol(key, "test-tenant", map[string]bool{"1.1.1.1": true})270 tu.WaitFor(t, "node-net-pol", 500*time.Millisecond,271 func(last bool) (bool, error) {272 cont.indexMutex.Lock()273 defer cont.indexMutex.Unlock()274 slice := apicapi.ApicSlice{sg}275 apicapi.PrepareApicSlice(slice, "kube", key)276 if !tu.WaitEqual(t, last, slice,277 cont.apicConn.GetDesiredState(key), "node-net-pol", key) {278 return false, nil279 }280 return true, nil281 })282 cont.stop()283}284func TestPodNetAnnotUpgrade(t *testing.T) {285 cont := testController()286 cont.config.PodIpPool = []ipam.IpRange{287 {Start: net.ParseIP("10.128.2.2"), End: net.ParseIP("10.128.16.1")},288 }289 cont.AciController.initIpam()290 cont.run()291 setupODev(cont, "node2", true)292 nodeAdder := func(id int, ips *metadata.NetIps) {293 nodeName := fmt.Sprintf("node%d", id)294 n := node(nodeName)295 raw, _ := json.Marshal(ips)296 n.ObjectMeta.Annotations[metadata.PodNetworkRangeAnnotation] = string(raw)297 cont.fakeNodeSource.Add(n)298 }299 // add 3 nodes300 ips1 := &metadata.NetIps{301 V4: []ipam.IpRange{302 {Start: net.ParseIP("10.128.2.2"), End: net.ParseIP("10.128.2.129")},303 },304 }305 ips2 := &metadata.NetIps{306 V4: []ipam.IpRange{307 {Start: net.ParseIP("10.128.3.2"), End: net.ParseIP("10.128.3.129")},308 },309 }310 ips3 := &metadata.NetIps{311 V4: []ipam.IpRange{312 {Start: net.ParseIP("10.128.2.130"), End: net.ParseIP("10.128.2.162")},313 },314 }315 nodeAdder(1, ips1)316 nodeAdder(2, ips2)317 nodeAdder(3, ips3)318 podAdder := func(n, start, end int) {319 nodeName := fmt.Sprintf("node%d", n)320 for ix := start; ix < end; ix++ {321 podName := fmt.Sprintf("testPod%d", ix)322 cont.fakeNodeSource.Add(node(nodeName))323 cont.fakePodSource.Add(podOnNode("testns", podName, nodeName))324 }325 }326 time.Sleep(time.Second)327 cont.nodeUpdates = nil328 podId := 1329 for total := 0; total < 120; total++ {330 podAdder(1, podId, podId+total)331 time.Sleep(2 * time.Millisecond)332 }333 ips4 := &metadata.NetIps{334 V4: []ipam.IpRange{335 {Start: net.ParseIP("10.128.2.2"), End: net.ParseIP("10.128.2.129")},336 {Start: net.ParseIP("10.128.2.163"), End: net.ParseIP("10.128.2.194")},337 },338 }339 waitForPodNetAnnot(t, cont, ips4, "node1 add")340 cont.stop()341}...

Full Screen

Full Screen

minikernel.go

Source:minikernel.go Github

copy

Full Screen

1package main2import (3 "encoding/json"4 "flag"5 "fmt"6 "io/ioutil"7 "os"8 "os/exec"9 "os/signal"10 "path"11 "strings"12 "syscall"13 "github.com/imdario/mergo"14 "inet.af/netaddr"15)16type arrayStringFlag []string17func (i *arrayStringFlag) String() string {18 return strings.Join([]string(*i), ",")19}20func (i *arrayStringFlag) Set(value string) error {21 *i = append(*i, value)22 return nil23}24var (25 nix9pPath = flag.String("nix9p-path", "result/nix-9p", "Path to the nix-9p binary.")26 firecrackerPath = flag.String("firecracker-path", "firecracker", "Path to the firecracker binary.")27 initrdPath = flag.String("initrd-path", "result/initrd", "Path to the initrd.")28 kernelPath = flag.String("kernel-path", "result/vmlinux", "Path to the kernel image.")29 id = flag.String("id", "default", "The unique identifier of this instance.")30 addr = flag.String("net", "198.51.100.1/30", "The network to use.")31 fsManifest = flag.String("fs-manifest", "", "The whitelisted set of nix store paths available in the minikernel.")32 onBringup = flag.String("on-bringup", "", "Store path to execute once the microVM comes up.")33 numCores = flag.Int("cores", 2, "Number of cores the microVM should have.")34 numMem = flag.Int("mem_mb", 512, "Amount of memory the microVM should have in megabytes.")35 allowUDP = flag.Bool("allow_udp", false, "Whether to permit UDP traffic.")36 allowTCP = flag.Bool("allow_tcp", false, "Whether to permit TCP traffic.")37 allowICMP = flag.Bool("allow_icmp", false, "Whether to permit ICMP traffic.")38 denySubnets arrayStringFlag39 denyRanges arrayStringFlag40 allowAddresses arrayStringFlag41 allowSubnets arrayStringFlag42 allowRanges arrayStringFlag43 unsafeFirecrackerOverrides = flag.String("unsafe_firecracker_overrides", "", "A JSON structure to arbitrarily override some configuration. Use at your own risk.")44)45func computeIPLists() (*netaddr.IPSet, *netaddr.IPSet, error) {46 var deny, allow netaddr.IPSetBuilder47 for _, s := range denySubnets {48 p, err := netaddr.ParseIPPrefix(s)49 if err != nil {50 return nil, nil, fmt.Errorf("parsing %q: %v", s, err)51 }52 deny.AddPrefix(p)53 }54 for _, r := range denyRanges {55 spl := strings.Split(r, "-")56 if len(spl) < 2 {57 return nil, nil, fmt.Errorf("parsing %q: %s", r, "expecting '-' separated ip range")58 }59 f, err := netaddr.ParseIP(spl[0])60 if err != nil {61 return nil, nil, fmt.Errorf("parsing %q from-address: %v", r, err)62 }63 t, err := netaddr.ParseIP(spl[1])64 if err != nil {65 return nil, nil, fmt.Errorf("parsing %q to-address: %v", r, err)66 }67 deny.AddRange(netaddr.IPRangeFrom(f, t))68 }69 for _, a := range allowAddresses {70 addr, err := netaddr.ParseIP(a)71 if err != nil {72 return nil, nil, fmt.Errorf("parsing %q allow-address: %v", a, err)73 }74 allow.Add(addr)75 }76 for _, s := range allowSubnets {77 p, err := netaddr.ParseIPPrefix(s)78 if err != nil {79 return nil, nil, fmt.Errorf("parsing %q: %v", s, err)80 }81 allow.AddPrefix(p)82 }83 for _, r := range allowRanges {84 spl := strings.Split(r, "-")85 if len(spl) < 2 {86 return nil, nil, fmt.Errorf("parsing %q: %s", r, "expecting '-' separated ip range")87 }88 f, err := netaddr.ParseIP(spl[0])89 if err != nil {90 return nil, nil, fmt.Errorf("parsing %q from-address: %v", r, err)91 }92 t, err := netaddr.ParseIP(spl[1])93 if err != nil {94 return nil, nil, fmt.Errorf("parsing %q to-address: %v", r, err)95 }96 allow.AddRange(netaddr.IPRangeFrom(f, t))97 }98 d, err := deny.IPSet()99 if err != nil {100 return nil, nil, fmt.Errorf("denylist: %v", err)101 }102 a, err := allow.IPSet()103 if err != nil {104 return nil, nil, fmt.Errorf("allowlist: %v", err)105 }106 return d, a, nil107}108func main() {109 flag.Var(&denySubnets, "ip4-deny-subnet", "IP networks which should not be externally reachable.")110 flag.Var(&denyRanges, "ip4-deny-range", "IP address ranges which should not be externally reachable.")111 flag.Var(&allowAddresses, "ip4-allow-addr", "IP address which should be reachable. Defaults to all if no ip-allow-* flags specified.")112 flag.Var(&allowSubnets, "ip4-allow-subnet", "IP networks which should be reachable. Defaults to all if no ip-allow-* flags specified.")113 flag.Var(&allowRanges, "ip4-allow-range", "IP address ranges which should be reachable. Defaults to all if no ip-allow-* flags specified.")114 flag.Parse()115 mk, err := newMinikernel()116 if err != nil {117 fmt.Fprintf(os.Stderr, "Failed to initialize: %v\n", err)118 os.Exit(1)119 }120 defer func() {121 if err := mk.Close(); err != nil {122 fmt.Fprintf(os.Stderr, "Shutdown failed: %v\n", err)123 }124 }()125 if err := mk.Start(); err != nil {126 fmt.Fprintf(os.Stderr, "Failed to start: %v\n", err)127 return128 }129 c := make(chan os.Signal)130 signal.Notify(c, os.Interrupt, syscall.SIGTERM)131 <-c132}133type mk struct {134 started bool135 wd string136 nc *netCtlr137 fs *fsDaemon138 vmm *exec.Cmd139}140func (mk *mk) Close() error {141 if mk.started {142 if err := mk.vmm.Process.Kill(); err != nil {143 return err144 }145 }146 if err := mk.fs.Close(); err != nil {147 return err148 }149 if err := mk.nc.Close(); err != nil {150 return err151 }152 return os.RemoveAll(mk.wd)153}154func (mk *mk) Start() error {155 if err := mk.nc.BringUp(); err != nil {156 return fmt.Errorf("net bringup: %v", err)157 }158 if err := mk.vmm.Start(); err != nil {159 return fmt.Errorf("vmm launch: %v", err)160 }161 mk.started = true162 return nil163}164func newMinikernel() (*mk, error) {165 wd, err := ioutil.TempDir("", "minikernel-"+*id)166 if err != nil {167 return nil, err168 }169 nc, err := newNet(wd, *addr)170 if err != nil {171 os.RemoveAll(wd)172 return nil, fmt.Errorf("net: %v", err)173 }174 fs, err := setupFS(wd)175 if err != nil {176 nc.Close()177 os.RemoveAll(wd)178 return nil, fmt.Errorf("fs: %v", err)179 }180 if err := writeFirecrackerConfig(wd, nc); err != nil {181 nc.Close()182 fs.Close()183 os.RemoveAll(wd)184 return nil, fmt.Errorf("vmm conf: %v", err)185 }186 vmm := exec.Command(*firecrackerPath, "--no-api", "--config-file", path.Join(wd, "firecracker_config.json"))187 vmm.Stdin = os.Stdin188 vmm.Stdout = os.Stdout189 vmm.Stderr = os.Stderr190 return &mk{191 wd: wd,192 fs: fs,193 nc: nc,194 vmm: vmm,195 }, nil196}197func writeFirecrackerConfig(wd string, nc *netCtlr) error {198 cf, err := os.OpenFile(path.Join(wd, "firecracker_config.json"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)199 if err != nil {200 return fmt.Errorf("conf: %v", err)201 }202 out := map[string]interface{}{203 "boot-source": map[string]interface{}{204 "kernel_image_path": *kernelPath,205 "boot_args": fmt.Sprintf("console=ttyS0 reboot=k panic=1 i8042.noaux mk-init.IP=%s mk-init.defaultRoute=%s mk-init.bringup=%s",206 nc.GuestAddr(), nc.hostAddr.IP.String(), *onBringup),207 "initrd_path": *initrdPath,208 },209 "drives": []string{},210 "machine-config": map[string]interface{}{211 "vcpu_count": *numCores,212 "mem_size_mib": *numMem,213 "track_dirty_pages": false,214 },215 "network-interfaces": []map[string]interface{}{216 {217 "iface_id": "1",218 "host_dev_name": nc.IFName(),219 "guest_mac": "06:00:c0:a8:00:02",220 "rx_rate_limiter": nil,221 "tx_rate_limiter": nil,222 },223 },224 "vsock": map[string]interface{}{225 "vsock_id": "fs",226 "uds_path": path.Join(wd, fsSockName),227 "guest_cid": 3,228 },229 }230 if *unsafeFirecrackerOverrides != "" {231 overlay := map[string]interface{}{}232 if err := json.Unmarshal([]byte(*unsafeFirecrackerOverrides), &overlay); err != nil {233 return fmt.Errorf("unsafe_firecracker_overrides: %v", err)234 }235 if err := mergo.Map(&out, overlay, mergo.WithSliceDeepCopy); err != nil {236 return fmt.Errorf("unsafe_firecracker_overrides: failed merge: %v", err)237 }238 }239 if err := json.NewEncoder(cf).Encode(out); err != nil {240 return fmt.Errorf("conf write: %v", err)241 }242 return cf.Close()243}...

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