feat: publish standalone worker
Separate worker packaging and service lifecycle from the control plane.
Этот коммит содержится в:
159
checks/cping/ping_test.go
Обычный файл
159
checks/cping/ping_test.go
Обычный файл
@@ -0,0 +1,159 @@
|
||||
package cping
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gorm.io/datatypes"
|
||||
|
||||
"rsgit.ru/rsmon/rsmon/app/models"
|
||||
)
|
||||
|
||||
// settings mirrors models.CheckSettings so the test can build a
|
||||
// CheckSettings JSON without pulling in the entire model package.
|
||||
type settings struct {
|
||||
Host string `json:"host,omitempty"`
|
||||
Count int `json:"count,omitempty"`
|
||||
Timeout int `json:"timeout,omitempty"`
|
||||
PacketSize int `json:"packet_size,omitempty"`
|
||||
Port string `json:"port,omitempty"`
|
||||
}
|
||||
|
||||
func newCheck(t *testing.T, s settings, host string) *models.Check {
|
||||
t.Helper()
|
||||
raw, err := json.Marshal(s)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal settings: %v", err)
|
||||
}
|
||||
if host == "" {
|
||||
host = "127.0.0.1"
|
||||
}
|
||||
return &models.Check{
|
||||
Kind: "ping",
|
||||
Monitor: &models.Monitor{Host: host},
|
||||
Settings: datatypes.JSON(raw),
|
||||
}
|
||||
}
|
||||
|
||||
// fakePinger returns canned stats without touching the network so the
|
||||
// state machine in Perform() can be exercised in CI environments
|
||||
// without CAP_NET_RAW.
|
||||
type fakePinger struct {
|
||||
stats Stats
|
||||
}
|
||||
|
||||
func (f *fakePinger) Run(host string, count int, timeout time.Duration, payloadSize int) Stats {
|
||||
return f.stats
|
||||
}
|
||||
|
||||
func TestPerformOK(t *testing.T) {
|
||||
SetPinger(&fakePinger{stats: Stats{PacketsSent: 3, PacketsRecv: 3, AvgRtt: 4 * time.Millisecond}})
|
||||
defer SetPinger(&realPinger{})
|
||||
|
||||
c := newCheck(t, settings{Count: 3}, "")
|
||||
r := Perform(c)
|
||||
if r.State != stateOK {
|
||||
t.Fatalf("expected OK, got %s (err=%v)", r.State, r.Error)
|
||||
}
|
||||
if r.PacketsSent != 3 || r.PacketsRecv != 3 {
|
||||
t.Fatalf("packet counts wrong: sent=%d recv=%d", r.PacketsSent, r.PacketsRecv)
|
||||
}
|
||||
if r.AvgRttMs < 1 {
|
||||
t.Fatalf("expected RTT > 0, got %v", r.AvgRttMs)
|
||||
}
|
||||
if len(r.Infos) == 0 || !strings.Contains(r.Infos[0], "rtt=") {
|
||||
t.Fatalf("expected rtt info line, got %v", r.Infos)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPerformNoReply(t *testing.T) {
|
||||
SetPinger(&fakePinger{stats: Stats{PacketsSent: 3, PacketsRecv: 0, Err: errors.New("i/o timeout")}})
|
||||
defer SetPinger(&realPinger{})
|
||||
|
||||
c := newCheck(t, settings{}, "")
|
||||
r := Perform(c)
|
||||
if r.State != stateERR {
|
||||
t.Fatalf("expected ERR, got %s", r.State)
|
||||
}
|
||||
if r.PacketsSent == 0 {
|
||||
t.Fatalf("expected PacketsSent to be incremented even on failure")
|
||||
}
|
||||
if r.Error == nil {
|
||||
t.Fatalf("expected error, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPerformUnsupported(t *testing.T) {
|
||||
SetPinger(&fakePinger{stats: Stats{Err: errors.New("socket: operation not permitted (cap_net_raw)")}})
|
||||
defer SetPinger(&realPinger{})
|
||||
|
||||
c := newCheck(t, settings{}, "")
|
||||
r := Perform(c)
|
||||
if r.State != stateFail {
|
||||
t.Fatalf("expected FAIL when raw ICMP is not allowed, got %s", r.State)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPerformEmptyHost(t *testing.T) {
|
||||
c := &models.Check{
|
||||
Kind: "ping",
|
||||
Monitor: &models.Monitor{Host: ""},
|
||||
Settings: datatypes.JSON("{}"),
|
||||
}
|
||||
r := Perform(c)
|
||||
if r.State != stateFail {
|
||||
t.Fatalf("expected FAIL on empty host, got %s", r.State)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsUnsupported(t *testing.T) {
|
||||
cases := []struct {
|
||||
err error
|
||||
want bool
|
||||
}{
|
||||
{err: nil, want: false},
|
||||
{err: errors.New(""), want: false},
|
||||
{err: errors.New("permission denied"), want: true},
|
||||
{err: errors.New("icmp listen: cap_net_raw required"), want: true},
|
||||
{err: errors.New("i/o timeout"), want: false},
|
||||
{err: errors.New("no route to host"), want: false},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
if got := isUnsupported(tc.err); got != tc.want {
|
||||
t.Errorf("isUnsupported(%q) = %v, want %v", tc.err, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLossPercent(t *testing.T) {
|
||||
cases := []struct {
|
||||
sent, recv int
|
||||
want int64
|
||||
}{
|
||||
{sent: 0, recv: 0, want: 0},
|
||||
{sent: 5, recv: 5, want: 0},
|
||||
{sent: 5, recv: 3, want: 40},
|
||||
{sent: 5, recv: 0, want: 100},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
if got := lossPercent(tc.sent, tc.recv); got != tc.want {
|
||||
t.Errorf("lossPercent(%d,%d) = %d, want %d", tc.sent, tc.recv, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeBytes(t *testing.T) {
|
||||
if got := makeBytes(0); len(got) != 0 {
|
||||
t.Fatalf("expected empty slice, got %d bytes", len(got))
|
||||
}
|
||||
if got := makeBytes(-1); len(got) != 0 {
|
||||
t.Fatalf("expected empty slice for negative size, got %d bytes", len(got))
|
||||
}
|
||||
got := makeBytes(3)
|
||||
if len(got) != 3 || string(got) != "abc" {
|
||||
t.Fatalf("expected 'abc', got %q", string(got))
|
||||
}
|
||||
}
|
||||
Ссылка в новой задаче
Block a user