feat: support ping command

This commit is contained in:
buyuxiang
2022-07-27 15:00:43 +08:00
parent 4132c324a4
commit 71da6d0556
4 changed files with 153 additions and 0 deletions

1
go.mod
View File

@@ -9,6 +9,7 @@ require (
github.com/getsentry/sentry-go v0.13.0
github.com/go-errors/errors v1.0.1
github.com/go-openapi/spec v0.20.6
github.com/go-ping/ping v1.1.0
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/google/uuid v1.3.0
github.com/gorilla/websocket v1.4.1

6
go.sum
View File

@@ -145,6 +145,8 @@ github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw=
github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
@@ -222,6 +224,7 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
@@ -343,6 +346,7 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0j
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -510,6 +514,7 @@ golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e h1:1SzTfNOXwIS2oWiMF+6qu0OUDKb0dauo6MoDUQyu+yU=
golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -615,6 +620,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

31
hrp/cmd/dial.go Normal file
View File

@@ -0,0 +1,31 @@
package cmd
import (
"time"
"github.com/spf13/cobra"
"github.com/httprunner/httprunner/v4/hrp/internal/dial"
)
var pingOptions dial.PingOptions
var pingCmd = &cobra.Command{
Use: "ping $url",
Short: "run integrated ping command",
Args: cobra.ExactArgs(1),
PreRun: func(cmd *cobra.Command, args []string) {
setLogLevel(logLevel)
},
RunE: func(cmd *cobra.Command, args []string) error {
return dial.DoPing(&pingOptions, args)
},
}
func init() {
rootCmd.AddCommand(pingCmd)
pingCmd.Flags().IntVarP(&pingOptions.Count, "count", "c", 10, "Stop after sending (and receiving) N packets")
pingCmd.Flags().DurationVarP(&pingOptions.Timeout, "timeout", "t", 20*time.Second, "Ping exits after N seconds")
pingCmd.Flags().DurationVarP(&pingOptions.Interval, "interval", "i", 1*time.Second, "Wait N seconds between sending each packet")
pingCmd.Flags().BoolVar(&pingOptions.SaveTests, "save-tests", false, "Save ping results json")
}

115
hrp/internal/dial/ping.go Normal file
View File

@@ -0,0 +1,115 @@
package dial
import (
"fmt"
"net/url"
"os"
"path/filepath"
"strings"
"time"
"github.com/go-ping/ping"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
)
type PingOptions struct {
Count int
Timeout time.Duration
Interval time.Duration
SaveTests bool
}
type PingResult struct {
Suc bool `json:"suc"`
ErrMsg string `json:"errMsg"`
Ip string `json:"ip"`
AvgCost int `json:"avgCost"`
MaxCost int `json:"maxCost"`
MinCost int `json:"minCost"`
Lost int `json:"lost"`
PingCount int `json:"pingCount"`
PacketSize int `json:"packetSize"`
ReceivePacketCount int `json:"receivePacketCount"`
SendPacketCount int `json:"sendPacketCount"`
SuccessCount int `json:"successCount"`
DebugLog string `json:"debugLog"`
}
func DoPing(pingOptions *PingOptions, args []string) (err error) {
if len(args) != 1 {
return errors.New("there should be one argument")
}
var pingResult PingResult
defer func() {
if pingOptions.SaveTests {
dir, _ := os.Getwd()
pingResultName := fmt.Sprintf("ping_result_%v.json", time.Now().Format("20060102150405"))
pingResultPath := filepath.Join(dir, pingResultName)
err = builtin.Dump2JSON(pingResult, pingResultPath)
if err != nil {
log.Error().Err(err).Msg("save ping result failed")
}
}
}()
pingTarget := args[0]
parsedURL, err := url.Parse(pingTarget)
if err == nil && parsedURL.Host != "" {
log.Info().Msgf("parse input url %v and extract host %v", pingTarget, parsedURL.Host)
pingTarget = strings.Split(parsedURL.Host, ":")[0]
}
log.Info().Msgf("ping host %v", pingTarget)
pinger, err := ping.NewPinger(pingTarget)
if err != nil {
log.Error().Err(err).Msgf("fail to get pinger for %s", pingTarget)
pingResult.Suc = false
pingResult.ErrMsg = err.Error()
pingResult.DebugLog = err.Error()
return
}
pinger.Count = pingOptions.Count
pinger.Timeout = pingOptions.Timeout
pinger.Interval = pingOptions.Interval
pinger.OnRecv = func(pkt *ping.Packet) {
pingResult.DebugLog += fmt.Sprintf("%d bytes from %s: icmp_seq=%d time=%v\n",
pkt.Nbytes, pkt.IPAddr, pkt.Seq, pkt.Rtt)
}
pinger.OnFinish = func(stats *ping.Statistics) {
pingResult.DebugLog += fmt.Sprintf("\n--- %s ping statistics ---\n", stats.Addr)
pingResult.DebugLog += fmt.Sprintf("%d packets transmitted, %d packets received, %v%% packet loss\n",
stats.PacketsSent, stats.PacketsRecv, stats.PacketLoss)
pingResult.DebugLog += fmt.Sprintf("round-trip min/avg/max/stddev = %v/%v/%v/%v\n",
stats.MinRtt, stats.AvgRtt, stats.MaxRtt, stats.StdDevRtt)
}
pingResult.DebugLog += fmt.Sprintf("PING %s (%s):\n", pinger.Addr(), pinger.IPAddr())
err = pinger.Run() // blocks until finished
if err != nil {
log.Error().Err(err).Msgf("fail to run ping for %s", parsedURL)
pingResult.Suc = false
pingResult.ErrMsg = err.Error()
pingResult.DebugLog = err.Error()
return
}
stats := pinger.Statistics() // get send/receive/rtt stats
pingResult.Ip = pinger.IPAddr().String()
pingResult.AvgCost = int(stats.AvgRtt / time.Millisecond)
pingResult.MaxCost = int(stats.MaxRtt / time.Millisecond)
pingResult.MinCost = int(stats.MinRtt / time.Millisecond)
pingResult.Lost = int(stats.PacketLoss)
pingResult.PingCount = pingOptions.Count
pingResult.PacketSize = pinger.Size
pingResult.ReceivePacketCount = stats.PacketsRecv
pingResult.SendPacketCount = stats.PacketsSent
pingResult.SuccessCount = stats.PacketsRecv
pingResult.Suc = true
pingResult.ErrMsg = ""
return
}