This commit is contained in:
Mikaël Cluseau
2018-07-06 19:13:18 +11:00
parent d76b49b3c5
commit 21d3f45969
442 changed files with 75578 additions and 0 deletions

1
vendor/github.com/sparrc/go-ping/.gitignore generated vendored Normal file
View File

@ -0,0 +1 @@
/ping

21
vendor/github.com/sparrc/go-ping/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Cameron Sparr
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

82
vendor/github.com/sparrc/go-ping/README.md generated vendored Normal file
View File

@ -0,0 +1,82 @@
# go-ping
[![GoDoc](https://godoc.org/github.com/sparrc/go-ping?status.svg)](https://godoc.org/github.com/sparrc/go-ping)
[![Circle CI](https://circleci.com/gh/sparrc/go-ping.svg?style=svg)](https://circleci.com/gh/sparrc/go-ping)
ICMP Ping library for Go, inspired by
[go-fastping](https://github.com/tatsushid/go-fastping)
Here is a very simple example that sends & receives 3 packets:
```go
pinger, err := ping.NewPinger("www.google.com")
if err != nil {
panic(err)
}
pinger.Count = 3
pinger.Run() // blocks until finished
stats := pinger.Statistics() // get send/receive/rtt stats
```
Here is an example that emulates the unix ping command:
```go
pinger, err := ping.NewPinger("www.google.com")
if err != nil {
panic(err)
}
pinger.OnRecv = func(pkt *ping.Packet) {
fmt.Printf("%d bytes from %s: icmp_seq=%d time=%v\n",
pkt.Nbytes, pkt.IPAddr, pkt.Seq, pkt.Rtt)
}
pinger.OnFinish = func(stats *ping.Statistics) {
fmt.Printf("\n--- %s ping statistics ---\n", stats.Addr)
fmt.Printf("%d packets transmitted, %d packets received, %v%% packet loss\n",
stats.PacketsSent, stats.PacketsRecv, stats.PacketLoss)
fmt.Printf("round-trip min/avg/max/stddev = %v/%v/%v/%v\n",
stats.MinRtt, stats.AvgRtt, stats.MaxRtt, stats.StdDevRtt)
}
fmt.Printf("PING %s (%s):\n", pinger.Addr(), pinger.IPAddr())
pinger.Run()
```
It sends ICMP packet(s) and waits for a response. If it receives a response,
it calls the "receive" callback. When it's finished, it calls the "finish"
callback.
For a full ping example, see
[cmd/ping/ping.go](https://github.com/sparrc/go-ping/blob/master/cmd/ping/ping.go)
## Installation:
```
go get github.com/sparrc/go-ping
```
To install the native Go ping executable:
```bash
go get github.com/sparrc/go-ping/...
$GOPATH/bin/ping
```
## Note on Linux Support:
This library attempts to send an
"unprivileged" ping via UDP. On linux, this must be enabled by setting
```
sudo sysctl -w net.ipv4.ping_group_range="0 2147483647"
```
If you do not wish to do this, you can set `pinger.SetPrivileged(true)` and
use setcap to allow your binary using go-ping to bind to raw sockets
(or just run as super-user):
```
setcap cap_net_raw=+ep /bin/goping-binary
```
See [this blog](https://sturmflut.github.io/linux/ubuntu/2015/01/17/unprivileged-icmp-sockets-on-linux/)
and [the Go icmp library](https://godoc.org/golang.org/x/net/icmp) for more details.

9
vendor/github.com/sparrc/go-ping/circle.yml generated vendored Normal file
View File

@ -0,0 +1,9 @@
test:
post:
- go build -race -o ping_linux ./cmd/ping/ping.go
- sudo ./ping_linux --privileged -c 2 www.google.com
- sudo ./ping_linux --privileged -c 3 -i 200ms www.google.com
- sudo ./ping_linux --privileged -c 10 -i 100ms -t 1s www.google.com
- GOOS=darwin go build -o ping_darwin ./cmd/ping/ping.go
- mv ping_linux $CIRCLE_ARTIFACTS
- mv ping_darwin $CIRCLE_ARTIFACTS

549
vendor/github.com/sparrc/go-ping/ping.go generated vendored Normal file
View File

@ -0,0 +1,549 @@
// Package ping is an ICMP ping library seeking to emulate the unix "ping"
// command.
//
// Here is a very simple example that sends & receives 3 packets:
//
// pinger, err := ping.NewPinger("www.google.com")
// if err != nil {
// panic(err)
// }
//
// pinger.Count = 3
// pinger.Run() // blocks until finished
// stats := pinger.Statistics() // get send/receive/rtt stats
//
// Here is an example that emulates the unix ping command:
//
// pinger, err := ping.NewPinger("www.google.com")
// if err != nil {
// fmt.Printf("ERROR: %s\n", err.Error())
// return
// }
//
// pinger.OnRecv = func(pkt *ping.Packet) {
// fmt.Printf("%d bytes from %s: icmp_seq=%d time=%v\n",
// pkt.Nbytes, pkt.IPAddr, pkt.Seq, pkt.Rtt)
// }
// pinger.OnFinish = func(stats *ping.Statistics) {
// fmt.Printf("\n--- %s ping statistics ---\n", stats.Addr)
// fmt.Printf("%d packets transmitted, %d packets received, %v%% packet loss\n",
// stats.PacketsSent, stats.PacketsRecv, stats.PacketLoss)
// fmt.Printf("round-trip min/avg/max/stddev = %v/%v/%v/%v\n",
// stats.MinRtt, stats.AvgRtt, stats.MaxRtt, stats.StdDevRtt)
// }
//
// fmt.Printf("PING %s (%s):\n", pinger.Addr(), pinger.IPAddr())
// pinger.Run()
//
// It sends ICMP packet(s) and waits for a response. If it receives a response,
// it calls the "receive" callback. When it's finished, it calls the "finish"
// callback.
//
// For a full ping example, see "cmd/ping/ping.go".
//
package ping
import (
"fmt"
"math"
"math/rand"
"net"
"os"
"os/signal"
"sync"
"syscall"
"time"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
)
const (
timeSliceLength = 8
protocolICMP = 1
protocolIPv6ICMP = 58
)
var (
ipv4Proto = map[string]string{"ip": "ip4:icmp", "udp": "udp4"}
ipv6Proto = map[string]string{"ip": "ip6:ipv6-icmp", "udp": "udp6"}
)
// NewPinger returns a new Pinger struct pointer
func NewPinger(addr string) (*Pinger, error) {
ipaddr, err := net.ResolveIPAddr("ip", addr)
if err != nil {
return nil, err
}
var ipv4 bool
if isIPv4(ipaddr.IP) {
ipv4 = true
} else if isIPv6(ipaddr.IP) {
ipv4 = false
}
return &Pinger{
ipaddr: ipaddr,
addr: addr,
Interval: time.Second,
Timeout: time.Second * 100000,
Count: -1,
network: "udp",
ipv4: ipv4,
size: timeSliceLength,
done: make(chan bool),
}, nil
}
// Pinger represents ICMP packet sender/receiver
type Pinger struct {
// Interval is the wait time between each packet send. Default is 1s.
Interval time.Duration
// Timeout specifies a timeout before ping exits, regardless of how many
// packets have been received.
Timeout time.Duration
// Count tells pinger to stop after sending (and receiving) Count echo
// packets. If this option is not specified, pinger will operate until
// interrupted.
Count int
// Debug runs in debug mode
Debug bool
// Number of packets sent
PacketsSent int
// Number of packets received
PacketsRecv int
// rtts is all of the Rtts
rtts []time.Duration
// OnRecv is called when Pinger receives and processes a packet
OnRecv func(*Packet)
// OnFinish is called when Pinger exits
OnFinish func(*Statistics)
// stop chan bool
done chan bool
ipaddr *net.IPAddr
addr string
ipv4 bool
source string
size int
sequence int
network string
}
type packet struct {
bytes []byte
nbytes int
}
// Packet represents a received and processed ICMP echo packet.
type Packet struct {
// Rtt is the round-trip time it took to ping.
Rtt time.Duration
// IPAddr is the address of the host being pinged.
IPAddr *net.IPAddr
// NBytes is the number of bytes in the message.
Nbytes int
// Seq is the ICMP sequence number.
Seq int
}
// Statistics represent the stats of a currently running or finished
// pinger operation.
type Statistics struct {
// PacketsRecv is the number of packets received.
PacketsRecv int
// PacketsSent is the number of packets sent.
PacketsSent int
// PacketLoss is the percentage of packets lost.
PacketLoss float64
// IPAddr is the address of the host being pinged.
IPAddr *net.IPAddr
// Addr is the string address of the host being pinged.
Addr string
// Rtts is all of the round-trip times sent via this pinger.
Rtts []time.Duration
// MinRtt is the minimum round-trip time sent via this pinger.
MinRtt time.Duration
// MaxRtt is the maximum round-trip time sent via this pinger.
MaxRtt time.Duration
// AvgRtt is the average round-trip time sent via this pinger.
AvgRtt time.Duration
// StdDevRtt is the standard deviation of the round-trip times sent via
// this pinger.
StdDevRtt time.Duration
}
// SetIPAddr sets the ip address of the target host.
func (p *Pinger) SetIPAddr(ipaddr *net.IPAddr) {
var ipv4 bool
if isIPv4(ipaddr.IP) {
ipv4 = true
} else if isIPv6(ipaddr.IP) {
ipv4 = false
}
p.ipaddr = ipaddr
p.addr = ipaddr.String()
p.ipv4 = ipv4
}
// IPAddr returns the ip address of the target host.
func (p *Pinger) IPAddr() *net.IPAddr {
return p.ipaddr
}
// SetAddr resolves and sets the ip address of the target host, addr can be a
// DNS name like "www.google.com" or IP like "127.0.0.1".
func (p *Pinger) SetAddr(addr string) error {
ipaddr, err := net.ResolveIPAddr("ip", addr)
if err != nil {
return err
}
p.SetIPAddr(ipaddr)
p.addr = addr
return nil
}
// Addr returns the string ip address of the target host.
func (p *Pinger) Addr() string {
return p.addr
}
// SetPrivileged sets the type of ping pinger will send.
// false means pinger will send an "unprivileged" UDP ping.
// true means pinger will send a "privileged" raw ICMP ping.
// NOTE: setting to true requires that it be run with super-user privileges.
func (p *Pinger) SetPrivileged(privileged bool) {
if privileged {
p.network = "ip"
} else {
p.network = "udp"
}
}
// Privileged returns whether pinger is running in privileged mode.
func (p *Pinger) Privileged() bool {
return p.network == "ip"
}
// Run runs the pinger. This is a blocking function that will exit when it's
// done. If Count or Interval are not specified, it will run continuously until
// it is interrupted.
func (p *Pinger) Run() {
p.run()
}
func (p *Pinger) run() {
var conn *icmp.PacketConn
if p.ipv4 {
if conn = p.listen(ipv4Proto[p.network], p.source); conn == nil {
return
}
} else {
if conn = p.listen(ipv6Proto[p.network], p.source); conn == nil {
return
}
}
defer conn.Close()
defer p.finish()
var wg sync.WaitGroup
recv := make(chan *packet, 5)
wg.Add(1)
go p.recvICMP(conn, recv, &wg)
err := p.sendICMP(conn)
if err != nil {
fmt.Println(err.Error())
}
timeout := time.NewTicker(p.Timeout)
interval := time.NewTicker(p.Interval)
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
signal.Notify(c, syscall.SIGTERM)
for {
select {
case <-c:
close(p.done)
case <-p.done:
wg.Wait()
return
case <-timeout.C:
close(p.done)
wg.Wait()
return
case <-interval.C:
err = p.sendICMP(conn)
if err != nil {
fmt.Println("FATAL: ", err.Error())
}
case r := <-recv:
err := p.processPacket(r)
if err != nil {
fmt.Println("FATAL: ", err.Error())
}
default:
if p.Count > 0 && p.PacketsRecv >= p.Count {
close(p.done)
wg.Wait()
return
}
}
}
}
func (p *Pinger) finish() {
handler := p.OnFinish
if handler != nil {
s := p.Statistics()
handler(s)
}
}
// Statistics returns the statistics of the pinger. This can be run while the
// pinger is running or after it is finished. OnFinish calls this function to
// get it's finished statistics.
func (p *Pinger) Statistics() *Statistics {
loss := float64(p.PacketsSent-p.PacketsRecv) / float64(p.PacketsSent) * 100
var min, max, total time.Duration
if len(p.rtts) > 0 {
min = p.rtts[0]
max = p.rtts[0]
}
for _, rtt := range p.rtts {
if rtt < min {
min = rtt
}
if rtt > max {
max = rtt
}
total += rtt
}
s := Statistics{
PacketsSent: p.PacketsSent,
PacketsRecv: p.PacketsRecv,
PacketLoss: loss,
Rtts: p.rtts,
Addr: p.addr,
IPAddr: p.ipaddr,
MaxRtt: max,
MinRtt: min,
}
if len(p.rtts) > 0 {
s.AvgRtt = total / time.Duration(len(p.rtts))
var sumsquares time.Duration
for _, rtt := range p.rtts {
sumsquares += (rtt - s.AvgRtt) * (rtt - s.AvgRtt)
}
s.StdDevRtt = time.Duration(math.Sqrt(
float64(sumsquares / time.Duration(len(p.rtts)))))
}
return &s
}
func (p *Pinger) recvICMP(
conn *icmp.PacketConn,
recv chan<- *packet,
wg *sync.WaitGroup,
) {
defer wg.Done()
for {
select {
case <-p.done:
return
default:
bytes := make([]byte, 512)
conn.SetReadDeadline(time.Now().Add(time.Millisecond * 100))
n, _, err := conn.ReadFrom(bytes)
if err != nil {
if neterr, ok := err.(*net.OpError); ok {
if neterr.Timeout() {
// Read timeout
continue
} else {
close(p.done)
return
}
}
}
recv <- &packet{bytes: bytes, nbytes: n}
}
}
}
func (p *Pinger) processPacket(recv *packet) error {
var bytes []byte
var proto int
if p.ipv4 {
if p.network == "ip" {
bytes = ipv4Payload(recv.bytes)
} else {
bytes = recv.bytes
}
proto = protocolICMP
} else {
bytes = recv.bytes
proto = protocolIPv6ICMP
}
var m *icmp.Message
var err error
if m, err = icmp.ParseMessage(proto, bytes[:recv.nbytes]); err != nil {
return fmt.Errorf("Error parsing icmp message")
}
if m.Type != ipv4.ICMPTypeEchoReply && m.Type != ipv6.ICMPTypeEchoReply {
// Not an echo reply, ignore it
return nil
}
outPkt := &Packet{
Nbytes: recv.nbytes,
IPAddr: p.ipaddr,
}
switch pkt := m.Body.(type) {
case *icmp.Echo:
outPkt.Rtt = time.Since(bytesToTime(pkt.Data[:timeSliceLength]))
outPkt.Seq = pkt.Seq
p.PacketsRecv += 1
default:
// Very bad, not sure how this can happen
return fmt.Errorf("Error, invalid ICMP echo reply. Body type: %T, %s",
pkt, pkt)
}
p.rtts = append(p.rtts, outPkt.Rtt)
handler := p.OnRecv
if handler != nil {
handler(outPkt)
}
return nil
}
func (p *Pinger) sendICMP(conn *icmp.PacketConn) error {
var typ icmp.Type
if p.ipv4 {
typ = ipv4.ICMPTypeEcho
} else {
typ = ipv6.ICMPTypeEchoRequest
}
var dst net.Addr = p.ipaddr
if p.network == "udp" {
dst = &net.UDPAddr{IP: p.ipaddr.IP, Zone: p.ipaddr.Zone}
}
t := timeToBytes(time.Now())
if p.size-timeSliceLength != 0 {
t = append(t, byteSliceOfSize(p.size-timeSliceLength)...)
}
bytes, err := (&icmp.Message{
Type: typ, Code: 0,
Body: &icmp.Echo{
ID: rand.Intn(65535),
Seq: p.sequence,
Data: t,
},
}).Marshal(nil)
if err != nil {
return err
}
for {
if _, err := conn.WriteTo(bytes, dst); err != nil {
if neterr, ok := err.(*net.OpError); ok {
if neterr.Err == syscall.ENOBUFS {
continue
}
}
}
p.PacketsSent += 1
p.sequence += 1
break
}
return nil
}
func (p *Pinger) listen(netProto string, source string) *icmp.PacketConn {
conn, err := icmp.ListenPacket(netProto, source)
if err != nil {
fmt.Printf("Error listening for ICMP packets: %s\n", err.Error())
close(p.done)
return nil
}
return conn
}
func byteSliceOfSize(n int) []byte {
b := make([]byte, n)
for i := 0; i < len(b); i++ {
b[i] = 1
}
return b
}
func ipv4Payload(b []byte) []byte {
if len(b) < ipv4.HeaderLen {
return b
}
hdrlen := int(b[0]&0x0f) << 2
return b[hdrlen:]
}
func bytesToTime(b []byte) time.Time {
var nsec int64
for i := uint8(0); i < 8; i++ {
nsec += int64(b[i]) << ((7 - i) * 8)
}
return time.Unix(nsec/1000000000, nsec%1000000000)
}
func isIPv4(ip net.IP) bool {
return len(ip.To4()) == net.IPv4len
}
func isIPv6(ip net.IP) bool {
return len(ip) == net.IPv6len
}
func timeToBytes(t time.Time) []byte {
nsec := t.UnixNano()
b := make([]byte, 8)
for i := uint8(0); i < 8; i++ {
b[i] = byte((nsec >> ((7 - i) * 8)) & 0xff)
}
return b
}

266
vendor/github.com/sparrc/go-ping/ping_test.go generated vendored Normal file
View File

@ -0,0 +1,266 @@
package ping
import (
"net"
"runtime/debug"
"testing"
"time"
)
func TestNewPingerValid(t *testing.T) {
p, err := NewPinger("www.google.com")
AssertNoError(t, err)
AssertEqualStrings(t, "www.google.com", p.Addr())
// DNS names should resolve into IP addresses
AssertNotEqualStrings(t, "www.google.com", p.IPAddr().String())
AssertTrue(t, isIPv4(p.IPAddr().IP))
AssertFalse(t, p.Privileged())
// Test that SetPrivileged works
p.SetPrivileged(true)
AssertTrue(t, p.Privileged())
// Test setting to ipv4 address
err = p.SetAddr("www.google.com")
AssertNoError(t, err)
AssertTrue(t, isIPv4(p.IPAddr().IP))
// Test setting to ipv6 address
err = p.SetAddr("ipv6.google.com")
AssertNoError(t, err)
AssertTrue(t, isIPv6(p.IPAddr().IP))
p, err = NewPinger("localhost")
AssertNoError(t, err)
AssertEqualStrings(t, "localhost", p.Addr())
// DNS names should resolve into IP addresses
AssertNotEqualStrings(t, "localhost", p.IPAddr().String())
AssertTrue(t, isIPv4(p.IPAddr().IP))
AssertFalse(t, p.Privileged())
// Test that SetPrivileged works
p.SetPrivileged(true)
AssertTrue(t, p.Privileged())
// Test setting to ipv4 address
err = p.SetAddr("www.google.com")
AssertNoError(t, err)
AssertTrue(t, isIPv4(p.IPAddr().IP))
// Test setting to ipv6 address
err = p.SetAddr("ipv6.google.com")
AssertNoError(t, err)
AssertTrue(t, isIPv6(p.IPAddr().IP))
p, err = NewPinger("127.0.0.1")
AssertNoError(t, err)
AssertEqualStrings(t, "127.0.0.1", p.Addr())
AssertTrue(t, isIPv4(p.IPAddr().IP))
AssertFalse(t, p.Privileged())
// Test that SetPrivileged works
p.SetPrivileged(true)
AssertTrue(t, p.Privileged())
// Test setting to ipv4 address
err = p.SetAddr("www.google.com")
AssertNoError(t, err)
AssertTrue(t, isIPv4(p.IPAddr().IP))
// Test setting to ipv6 address
err = p.SetAddr("ipv6.google.com")
AssertNoError(t, err)
AssertTrue(t, isIPv6(p.IPAddr().IP))
p, err = NewPinger("ipv6.google.com")
AssertNoError(t, err)
AssertEqualStrings(t, "ipv6.google.com", p.Addr())
// DNS names should resolve into IP addresses
AssertNotEqualStrings(t, "ipv6.google.com", p.IPAddr().String())
AssertTrue(t, isIPv6(p.IPAddr().IP))
AssertFalse(t, p.Privileged())
// Test that SetPrivileged works
p.SetPrivileged(true)
AssertTrue(t, p.Privileged())
// Test setting to ipv4 address
err = p.SetAddr("www.google.com")
AssertNoError(t, err)
AssertTrue(t, isIPv4(p.IPAddr().IP))
// Test setting to ipv6 address
err = p.SetAddr("ipv6.google.com")
AssertNoError(t, err)
AssertTrue(t, isIPv6(p.IPAddr().IP))
// ipv6 localhost:
p, err = NewPinger("::1")
AssertNoError(t, err)
AssertEqualStrings(t, "::1", p.Addr())
AssertTrue(t, isIPv6(p.IPAddr().IP))
AssertFalse(t, p.Privileged())
// Test that SetPrivileged works
p.SetPrivileged(true)
AssertTrue(t, p.Privileged())
// Test setting to ipv4 address
err = p.SetAddr("www.google.com")
AssertNoError(t, err)
AssertTrue(t, isIPv4(p.IPAddr().IP))
// Test setting to ipv6 address
err = p.SetAddr("ipv6.google.com")
AssertNoError(t, err)
AssertTrue(t, isIPv6(p.IPAddr().IP))
}
func TestNewPingerInvalid(t *testing.T) {
_, err := NewPinger("127.0.0.0.1")
AssertError(t, err, "127.0.0.0.1")
_, err = NewPinger("127..0.0.1")
AssertError(t, err, "127..0.0.1")
_, err = NewPinger("wtf")
AssertError(t, err, "wtf")
_, err = NewPinger(":::1")
AssertError(t, err, ":::1")
_, err = NewPinger("ipv5.google.com")
AssertError(t, err, "ipv5.google.com")
}
func TestSetIPAddr(t *testing.T) {
googleaddr, err := net.ResolveIPAddr("ip", "www.google.com")
if err != nil {
t.Fatal("Can't resolve www.google.com, can't run tests")
}
// Create a localhost ipv4 pinger
p, err := NewPinger("localhost")
AssertNoError(t, err)
AssertEqualStrings(t, "localhost", p.Addr())
// set IPAddr to google
p.SetIPAddr(googleaddr)
AssertEqualStrings(t, googleaddr.String(), p.Addr())
}
func TestStatisticsSunny(t *testing.T) {
// Create a localhost ipv4 pinger
p, err := NewPinger("localhost")
AssertNoError(t, err)
AssertEqualStrings(t, "localhost", p.Addr())
p.PacketsSent = 10
p.PacketsRecv = 10
p.rtts = []time.Duration{
time.Duration(1000),
time.Duration(1000),
time.Duration(1000),
time.Duration(1000),
time.Duration(1000),
time.Duration(1000),
time.Duration(1000),
time.Duration(1000),
time.Duration(1000),
time.Duration(1000),
}
stats := p.Statistics()
if stats.PacketsRecv != 10 {
t.Errorf("Expected %v, got %v", 10, stats.PacketsRecv)
}
if stats.PacketsSent != 10 {
t.Errorf("Expected %v, got %v", 10, stats.PacketsSent)
}
if stats.PacketLoss != 0 {
t.Errorf("Expected %v, got %v", 0, stats.PacketLoss)
}
if stats.MinRtt != time.Duration(1000) {
t.Errorf("Expected %v, got %v", time.Duration(1000), stats.MinRtt)
}
if stats.MaxRtt != time.Duration(1000) {
t.Errorf("Expected %v, got %v", time.Duration(1000), stats.MaxRtt)
}
if stats.AvgRtt != time.Duration(1000) {
t.Errorf("Expected %v, got %v", time.Duration(1000), stats.AvgRtt)
}
if stats.StdDevRtt != time.Duration(0) {
t.Errorf("Expected %v, got %v", time.Duration(0), stats.StdDevRtt)
}
}
func TestStatisticsLossy(t *testing.T) {
// Create a localhost ipv4 pinger
p, err := NewPinger("localhost")
AssertNoError(t, err)
AssertEqualStrings(t, "localhost", p.Addr())
p.PacketsSent = 20
p.PacketsRecv = 10
p.rtts = []time.Duration{
time.Duration(10),
time.Duration(1000),
time.Duration(1000),
time.Duration(10000),
time.Duration(1000),
time.Duration(800),
time.Duration(1000),
time.Duration(40),
time.Duration(100000),
time.Duration(1000),
}
stats := p.Statistics()
if stats.PacketsRecv != 10 {
t.Errorf("Expected %v, got %v", 10, stats.PacketsRecv)
}
if stats.PacketsSent != 20 {
t.Errorf("Expected %v, got %v", 20, stats.PacketsSent)
}
if stats.PacketLoss != 50 {
t.Errorf("Expected %v, got %v", 50, stats.PacketLoss)
}
if stats.MinRtt != time.Duration(10) {
t.Errorf("Expected %v, got %v", time.Duration(10), stats.MinRtt)
}
if stats.MaxRtt != time.Duration(100000) {
t.Errorf("Expected %v, got %v", time.Duration(100000), stats.MaxRtt)
}
if stats.AvgRtt != time.Duration(11585) {
t.Errorf("Expected %v, got %v", time.Duration(11585), stats.AvgRtt)
}
if stats.StdDevRtt != time.Duration(29603) {
t.Errorf("Expected %v, got %v", time.Duration(29603), stats.StdDevRtt)
}
}
// Test helpers
func AssertNoError(t *testing.T, err error) {
if err != nil {
t.Errorf("Expected No Error but got %s, Stack:\n%s",
err, string(debug.Stack()))
}
}
func AssertError(t *testing.T, err error, info string) {
if err == nil {
t.Errorf("Expected Error but got %s, %s, Stack:\n%s",
err, info, string(debug.Stack()))
}
}
func AssertEqualStrings(t *testing.T, expected, actual string) {
if expected != actual {
t.Errorf("Expected %s, got %s, Stack:\n%s",
expected, actual, string(debug.Stack()))
}
}
func AssertNotEqualStrings(t *testing.T, expected, actual string) {
if expected == actual {
t.Errorf("Expected %s, got %s, Stack:\n%s",
expected, actual, string(debug.Stack()))
}
}
func AssertTrue(t *testing.T, b bool) {
if !b {
t.Errorf("Expected True, got False, Stack:\n%s", string(debug.Stack()))
}
}
func AssertFalse(t *testing.T, b bool) {
if b {
t.Errorf("Expected False, got True, Stack:\n%s", string(debug.Stack()))
}
}