This commit is contained in:
crusader 2018-09-17 21:45:26 +09:00
parent 2423d92777
commit 53acbc1c03
8 changed files with 166 additions and 95 deletions

View File

@ -6,41 +6,109 @@ import (
"strings" "strings"
) )
type PingOptions struct { type Option interface {
Retry int Retry() int
Interval int Interval() int
Deadline int Deadline() int
Validate()
} }
type Response struct { type Response interface {
TTL int TTL() int
Time float32 Time() float32
} }
type Summary struct { type Summary interface {
SendCount int SendCount() int
ReceiveCount int ReceiveCount() int
LossPercent float32 LossPercent() float32
MinTime float32 MinTime() float32
MaxTime float32 MaxTime() float32
AvgTime float32 AvgTime() float32
}
type Result interface {
Responses() map[int]Response
Summary() Summary
}
type PingOption struct {
retry int
interval int
deadline int
}
func (o *PingOption) Retry() int {
return o.retry
}
func (o *PingOption) Interval() int {
return o.interval
}
func (o *PingOption) Deadline() int {
return o.deadline
}
func (o *PingOption) Validate() {
if 0 >= o.retry {
o.retry = 1
}
if 0 >= o.interval {
o.interval = 1
}
if 0 >= o.deadline {
o.deadline = 1
}
}
type PingResponse struct {
ttl int
time float32
}
func (r *PingResponse) TTL() int {
return r.ttl
}
func (r *PingResponse) Time() float32 {
return r.time
}
type PingSummary struct {
sendCount int
receiveCount int
lossPercent float32
minTime float32
maxTime float32
avgTime float32
}
func (s *PingSummary) SendCount() int {
return s.sendCount
}
func (s *PingSummary) ReceiveCount() int {
return s.receiveCount
}
func (s *PingSummary) LossPercent() float32 {
return s.lossPercent
}
func (s *PingSummary) MinTime() float32 {
return s.minTime
}
func (s *PingSummary) MaxTime() float32 {
return s.maxTime
}
func (s *PingSummary) AvgTime() float32 {
return s.avgTime
} }
type PingResult struct { type PingResult struct {
Responses map[int]*Response responses map[int]Response
Summary *Summary summary Summary
} }
func (o *PingOptions) Validate() { func (r *PingResult) Responses() map[int]Response {
if 0 >= o.Retry { return r.responses
o.Retry = 1
}
if 0 >= o.Interval {
o.Interval = 1
}
if 0 >= o.Deadline {
o.Deadline = 1
} }
func (r *PingResult) Summary() Summary {
return r.summary
} }
// $ ping 192.168.1.1 -c 7 -i 1 -w 0.3 // $ ping 192.168.1.1 -c 7 -i 1 -w 0.3
@ -54,10 +122,10 @@ func (o *PingOptions) Validate() {
// --- 192.168.1.1 ping statistics --- // --- 192.168.1.1 ping statistics ---
// 7 packets transmitted, 4 received, 42% packet loss, time 6010ms // 7 packets transmitted, 4 received, 42% packet loss, time 6010ms
// rtt min/avg/max/mdev = 0.163/0.253/0.344/0.082 ms // rtt min/avg/max/mdev = 0.163/0.253/0.344/0.082 ms
func parseLinuxPing(output []byte) (*PingResult, error) { func parseLinuxPing(output []byte) (Result, error) {
result := &PingResult{ result := &PingResult{
Responses: make(map[int]*Response, 0), responses: make(map[int]Response, 0),
Summary: &Summary{}, summary: &PingSummary{},
} }
lines := strings.Split(string(output), "\n") lines := strings.Split(string(output), "\n")
@ -77,21 +145,21 @@ LOOP:
log.Print(err) log.Print(err)
continue LOOP continue LOOP
} }
result.Summary.MinTime = float32(minTime) result.summary.(*PingSummary).minTime = float32(minTime)
maxTime, err := strconv.ParseFloat(times[2], 32) maxTime, err := strconv.ParseFloat(times[2], 32)
if nil != err { if nil != err {
log.Print(err) log.Print(err)
continue LOOP continue LOOP
} }
result.Summary.MaxTime = float32(maxTime) result.summary.(*PingSummary).maxTime = float32(maxTime)
avgTime, err := strconv.ParseFloat(times[1], 32) avgTime, err := strconv.ParseFloat(times[1], 32)
if nil != err { if nil != err {
log.Print(err) log.Print(err)
continue LOOP continue LOOP
} }
result.Summary.AvgTime = float32(avgTime) result.summary.(*PingSummary).avgTime = float32(avgTime)
case 8: case 8:
if "bytes" != fields[1] || "from" != fields[2] { if "bytes" != fields[1] || "from" != fields[2] {
@ -117,9 +185,9 @@ LOOP:
continue LOOP continue LOOP
} }
result.Responses[seq] = &Response{ result.responses[seq] = &PingResponse{
TTL: ttl, ttl: ttl,
Time: float32(_time), time: float32(_time),
} }
case 10: case 10:
@ -128,21 +196,21 @@ LOOP:
log.Print(err) log.Print(err)
continue LOOP continue LOOP
} }
result.Summary.SendCount = sendCount result.summary.(*PingSummary).sendCount = sendCount
receiveCount, err := strconv.Atoi(fields[3]) receiveCount, err := strconv.Atoi(fields[3])
if nil != err { if nil != err {
log.Print(err) log.Print(err)
continue LOOP continue LOOP
} }
result.Summary.ReceiveCount = receiveCount result.summary.(*PingSummary).receiveCount = receiveCount
lossPercent, err := strconv.ParseFloat(strings.Replace(fields[5], "%", "", -1), 32) lossPercent, err := strconv.ParseFloat(strings.Replace(fields[5], "%", "", -1), 32)
if nil != err { if nil != err {
log.Print(err) log.Print(err)
continue LOOP continue LOOP
} }
result.Summary.LossPercent = float32(lossPercent) result.summary.(*PingSummary).lossPercent = float32(lossPercent)
} }
} }
@ -178,10 +246,10 @@ LOOP:
// Approximate round trip times in milli-seconds: // Approximate round trip times in milli-seconds:
// Minimum = 37ms, Maximum = 38ms, Average = 37ms // Minimum = 37ms, Maximum = 38ms, Average = 37ms
func parseWindowsPing(output []byte) (*PingResult, error) { func parseWindowsPing(output []byte) (Result, error) {
result := &PingResult{ result := &PingResult{
Responses: make(map[int]*Response, 0), responses: make(map[int]Response, 0),
Summary: &Summary{}, summary: &PingSummary{},
} }
lines := strings.Split(string(output), "\n") lines := strings.Split(string(output), "\n")
@ -218,9 +286,9 @@ LOOP:
continue LOOP continue LOOP
} }
result.Responses[seq] = &Response{ result.responses[seq] = &PingResponse{
TTL: ttl, ttl: ttl,
Time: float32(_time), time: float32(_time),
} }
seq = seq + 1 seq = seq + 1
case 9: case 9:
@ -235,7 +303,7 @@ LOOP:
log.Print(err) log.Print(err)
continue LOOP continue LOOP
} }
result.Summary.MinTime = float32(minTime) result.summary.(*PingSummary).minTime = float32(minTime)
maxTimes := strings.Replace(fields[5], "ms", "", -1) maxTimes := strings.Replace(fields[5], "ms", "", -1)
maxTimes = strings.Replace(maxTimes, ",", "", -1) maxTimes = strings.Replace(maxTimes, ",", "", -1)
@ -244,7 +312,7 @@ LOOP:
log.Print(err) log.Print(err)
continue LOOP continue LOOP
} }
result.Summary.MaxTime = float32(maxTime) result.summary.(*PingSummary).maxTime = float32(maxTime)
avgTimes := strings.Replace(fields[8], "ms", "", -1) avgTimes := strings.Replace(fields[8], "ms", "", -1)
avgTime, err := strconv.ParseFloat(avgTimes, 32) avgTime, err := strconv.ParseFloat(avgTimes, 32)
@ -252,7 +320,7 @@ LOOP:
log.Print(err) log.Print(err)
continue LOOP continue LOOP
} }
result.Summary.AvgTime = float32(avgTime) result.summary.(*PingSummary).avgTime = float32(avgTime)
case 12: case 12:
if "Packets:" != fields[0] { if "Packets:" != fields[0] {
@ -263,14 +331,14 @@ LOOP:
log.Print(err) log.Print(err)
continue LOOP continue LOOP
} }
result.Summary.SendCount = sendCount result.summary.(*PingSummary).sendCount = sendCount
receiveCount, err := strconv.Atoi(strings.Replace(fields[6], ",", "", -1)) receiveCount, err := strconv.Atoi(strings.Replace(fields[6], ",", "", -1))
if nil != err { if nil != err {
log.Print(err) log.Print(err)
continue LOOP continue LOOP
} }
result.Summary.ReceiveCount = receiveCount result.summary.(*PingSummary).receiveCount = receiveCount
lossPercents := strings.Replace(fields[10], "(", "", -1) lossPercents := strings.Replace(fields[10], "(", "", -1)
lossPercents = strings.Replace(lossPercents, "%", "", -1) lossPercents = strings.Replace(lossPercents, "%", "", -1)
@ -279,7 +347,7 @@ LOOP:
log.Print(err) log.Print(err)
continue LOOP continue LOOP
} }
result.Summary.LossPercent = float32(lossPercent) result.summary.(*PingSummary).lossPercent = float32(lossPercent)
} }
} }
@ -297,10 +365,10 @@ LOOP:
// --- 192.168.1.1 ping statistics --- // --- 192.168.1.1 ping statistics ---
// 5 packets transmitted, 5 packets received, 0.0% packet loss // 5 packets transmitted, 5 packets received, 0.0% packet loss
// round-trip min/avg/max/stddev = 0.971/2.760/3.934/1.204 ms // round-trip min/avg/max/stddev = 0.971/2.760/3.934/1.204 ms
func parseDarwinPing(output []byte) (*PingResult, error) { func parseDarwinPing(output []byte) (Result, error) {
result := &PingResult{ result := &PingResult{
Responses: make(map[int]*Response, 0), responses: make(map[int]Response, 0),
Summary: &Summary{}, summary: &PingSummary{},
} }
lines := strings.Split(string(output), "\n") lines := strings.Split(string(output), "\n")
@ -320,21 +388,21 @@ LOOP:
log.Print(err) log.Print(err)
continue LOOP continue LOOP
} }
result.Summary.MinTime = float32(minTime) result.summary.(*PingSummary).minTime = float32(minTime)
maxTime, err := strconv.ParseFloat(times[2], 32) maxTime, err := strconv.ParseFloat(times[2], 32)
if nil != err { if nil != err {
log.Print(err) log.Print(err)
continue LOOP continue LOOP
} }
result.Summary.MaxTime = float32(maxTime) result.summary.(*PingSummary).maxTime = float32(maxTime)
avgTime, err := strconv.ParseFloat(times[1], 32) avgTime, err := strconv.ParseFloat(times[1], 32)
if nil != err { if nil != err {
log.Print(err) log.Print(err)
continue LOOP continue LOOP
} }
result.Summary.AvgTime = float32(avgTime) result.summary.(*PingSummary).avgTime = float32(avgTime)
case 8: case 8:
if "bytes" != fields[1] || "from" != fields[2] { if "bytes" != fields[1] || "from" != fields[2] {
@ -360,9 +428,9 @@ LOOP:
continue LOOP continue LOOP
} }
result.Responses[seq] = &Response{ result.responses[seq] = &PingResponse{
TTL: ttl, ttl: ttl,
Time: float32(_time), time: float32(_time),
} }
case 9: case 9:
@ -371,21 +439,21 @@ LOOP:
log.Print(err) log.Print(err)
continue LOOP continue LOOP
} }
result.Summary.SendCount = sendCount result.summary.(*PingSummary).sendCount = sendCount
receiveCount, err := strconv.Atoi(fields[3]) receiveCount, err := strconv.Atoi(fields[3])
if nil != err { if nil != err {
log.Print(err) log.Print(err)
continue LOOP continue LOOP
} }
result.Summary.ReceiveCount = receiveCount result.summary.(*PingSummary).receiveCount = receiveCount
lossPercent, err := strconv.ParseFloat(strings.Replace(fields[6], "%", "", -1), 32) lossPercent, err := strconv.ParseFloat(strings.Replace(fields[6], "%", "", -1), 32)
if nil != err { if nil != err {
log.Print(err) log.Print(err)
continue LOOP continue LOOP
} }
result.Summary.LossPercent = float32(lossPercent) result.summary.(*PingSummary).lossPercent = float32(lossPercent)
} }
} }

View File

@ -5,13 +5,13 @@ import (
"os/exec" "os/exec"
) )
func Ping(destination string, options *PingOptions) (*PingResult, error) { func Ping(destination string, options Option) (Result, error) {
options.Validate() option.Validate()
params := make([]string, 0) params := make([]string, 0)
params = append(params, destination) params = append(params, destination)
params = append(params, fmt.Sprintf("-c %d", options.Retry)) params = append(params, fmt.Sprintf("-c %d", option.Retry()))
params = append(params, fmt.Sprintf("-i %d", options.Interval)) params = append(params, fmt.Sprintf("-i %d", option.Interval()))
pCmd := exec.Command("ping", params...) pCmd := exec.Command("ping", params...)
output, err := pCmd.CombinedOutput() output, err := pCmd.CombinedOutput()

View File

@ -8,27 +8,27 @@ import (
func TestPing(t *testing.T) { func TestPing(t *testing.T) {
type args struct { type args struct {
destination string destination string
options *PingOptions option Option
} }
tests := []struct { tests := []struct {
name string name string
args args args args
want *PingResult want Result
wantErr bool wantErr bool
}{ }{
{ {
name: "192.168.1.1", name: "192.168.1.1",
args: args{ args: args{
destination: "192.168.1.1", destination: "192.168.1.1",
options: &PingOptions{ option: &PingOption{
Retry: 4, retry: 4,
}, },
}, },
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got, err := Ping(tt.args.destination, tt.args.options) got, err := Ping(tt.args.destination, tt.args.option)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Errorf("Ping() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("Ping() error = %v, wantErr %v", err, tt.wantErr)
return return

View File

@ -2,21 +2,23 @@ package ping
import ( import (
"fmt" "fmt"
"log"
"os/exec" "os/exec"
) )
func Ping(destination string, options *PingOptions) (*PingResult, error) { func Ping(destination string, option Option) (Result, error) {
options.Validate() option.Validate()
params := make([]string, 0) params := make([]string, 0)
params = append(params, destination) params = append(params, destination)
params = append(params, fmt.Sprintf("-c %d", options.Retry)) params = append(params, fmt.Sprintf("-c %d", option.Retry()))
params = append(params, fmt.Sprintf("-i %d", options.Interval)) params = append(params, fmt.Sprintf("-i %d", option.Interval()))
params = append(params, fmt.Sprintf("-w %d", options.Deadline))
pCmd := exec.Command("ping", params...) pCmd := exec.Command("ping", params...)
log.Print(pCmd.Args)
output, err := pCmd.CombinedOutput() output, err := pCmd.CombinedOutput()
if err != nil { if err != nil {
log.Print(err)
return nil, err return nil, err
} }

View File

@ -5,27 +5,27 @@ import "testing"
func TestPing(t *testing.T) { func TestPing(t *testing.T) {
type args struct { type args struct {
destination string destination string
options *PingOptions option Option
} }
tests := []struct { tests := []struct {
name string name string
args args args args
want *PingResult want Result
wantErr bool wantErr bool
}{ }{
{ {
name: "192.168.1.1", name: "192.168.1.1",
args: args{ args: args{
destination: "192.168.1.1", destination: "192.168.1.1",
options: &PingOptions{ option: &PingOption{
Retry: 4, retry: 4,
}, },
}, },
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got, err := Ping(tt.args.destination, tt.args.options) got, err := Ping(tt.args.destination, tt.args.option)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Errorf("Ping() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("Ping() error = %v, wantErr %v", err, tt.wantErr)
return return

View File

@ -17,12 +17,13 @@ func TestPingOptions_Validate(t *testing.T) {
}{ }{
// TODO: Add test cases. // TODO: Add test cases.
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
o := &PingOptions{ o := &PingOption{
Retry: tt.fields.Retry, retry: tt.fields.Retry,
Interval: tt.fields.Interval, interval: tt.fields.Interval,
Deadline: tt.fields.Deadline, deadline: tt.fields.Deadline,
} }
o.Validate() o.Validate()
}) })
@ -62,7 +63,7 @@ func Test_parseWindowsPing(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
args args args args
want *PingResult want Result
wantErr bool wantErr bool
}{ }{
{ {
@ -108,7 +109,7 @@ func Test_parseDarwinPing(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
args args args args
want *PingResult want Result
wantErr bool wantErr bool
}{ }{
{ {

View File

@ -5,12 +5,12 @@ import (
"os/exec" "os/exec"
) )
func Ping(destination string, options *PingOptions) (*PingResult, error) { func Ping(destination string, option Option) (Result, error) {
options.Validate() option.Validate()
params := make([]string, 0) params := make([]string, 0)
params = append(params, "/C") params = append(params, "/C")
params = append(params, fmt.Sprintf("chcp 437 && ping %s -n %d -w %d", destination, options.Retry, options.Deadline*1000)) params = append(params, fmt.Sprintf("chcp 437 && ping %s -n %d -w %d", destination, option.Retry(), option.Deadline()*1000))
pCmd := exec.Command("cmd.exe", params...) pCmd := exec.Command("cmd.exe", params...)
output, err := pCmd.CombinedOutput() output, err := pCmd.CombinedOutput()

View File

@ -5,27 +5,27 @@ import "testing"
func TestPing(t *testing.T) { func TestPing(t *testing.T) {
type args struct { type args struct {
destination string destination string
options *PingOptions option Option
} }
tests := []struct { tests := []struct {
name string name string
args args args args
want *PingResult want Result
wantErr bool wantErr bool
}{ }{
{ {
name: "192.168.1.1", name: "192.168.1.1",
args: args{ args: args{
destination: "192.168.1.1", destination: "192.168.1.1",
options: &PingOptions{ option: &PingOption{
Retry: 4, retry: 4,
}, },
}, },
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got, err := Ping(tt.args.destination, tt.args.options) got, err := Ping(tt.args.destination, tt.args.option)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Errorf("Ping() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("Ping() error = %v, wantErr %v", err, tt.wantErr)
return return