tests: fixed several tests

This commit is contained in:
yusing 2025-04-18 03:54:45 +08:00
parent 98777205a5
commit d4acd99fa7
10 changed files with 137 additions and 97 deletions

View file

@ -11,14 +11,12 @@ import (
var ep = NewEntrypoint()
func addRoute(alias string) *route.ReveseProxyRoute {
r := &route.ReveseProxyRoute{
func addRoute(alias string) {
routes.HTTP.Add(&route.ReveseProxyRoute{
Route: &route.Route{
Alias: alias,
},
}
routes.HTTP.Add(r)
return r
})
}
func run(t *testing.T, match []string, noMatch []string) {
@ -28,10 +26,9 @@ func run(t *testing.T, match []string, noMatch []string) {
for _, test := range match {
t.Run(test, func(t *testing.T) {
r := addRoute(test)
found, err := ep.findRouteFunc(test)
expect.NoError(t, err)
expect.True(t, found == r)
expect.NotNil(t, found)
})
}
@ -112,7 +109,7 @@ func TestFindRouteByDomainsExactMatch(t *testing.T) {
".sub.domain.com",
})
addRoute("app1")
addRoute("app1.foo.bar")
tests := []string{
"app1.foo.bar", // exact match

View file

@ -1,7 +1,6 @@
package systeminfo
import (
"bytes"
"context"
"errors"
"fmt"
@ -295,48 +294,46 @@ func (s *SystemInfo) collectSensorsInfo(ctx context.Context) error {
}
// explicitly implement MarshalJSON to avoid reflection
func (s *SystemInfo) MarshalJSONTo(buf []byte) []byte {
b := bytes.NewBuffer(buf)
b.WriteRune('{')
func (s *SystemInfo) MarshalJSONTo(b []byte) []byte {
b = append(b, '{')
// timestamp
b.WriteString(`"timestamp":`)
b.WriteString(strconv.FormatInt(s.Timestamp, 10))
b = append(b, `"timestamp":`...)
b = strconv.AppendInt(b, s.Timestamp, 10)
// cpu_average
b.WriteString(`,"cpu_average":`)
b = append(b, `,"cpu_average":`...)
if s.CPUAverage != nil {
b.WriteString(strconv.FormatFloat(*s.CPUAverage, 'f', 2, 64))
b = strconv.AppendFloat(b, *s.CPUAverage, 'f', 2, 64)
} else {
b.WriteString("null")
b = append(b, "null"...)
}
// memory
b.WriteString(`,"memory":`)
b = append(b, `,"memory":`...)
if s.Memory != nil {
b.Write(fmt.Appendf(nil,
b = fmt.Appendf(b,
`{"total":%d,"available":%d,"used":%d,"used_percent":%s}`,
s.Memory.Total,
s.Memory.Available,
s.Memory.Used,
strconv.FormatFloat(s.Memory.UsedPercent, 'f', 2, 64),
))
)
} else {
b.WriteString("null")
b = append(b, "null"...)
}
// disk
b.WriteString(`,"disks":`)
b = append(b, `,"disks":`...)
if len(s.Disks) > 0 {
b.WriteRune('{')
b = append(b, '{')
first := true
for device, disk := range s.Disks {
if !first {
b.WriteRune(',')
b = append(b, ',')
}
b.Write(fmt.Appendf(nil,
`"%s":{"device":%q,"path":%q,"fstype":%q,"total":%d,"free":%d,"used":%d,"used_percent":%s}`,
b = fmt.Appendf(b,
`"%s":{"device":%q,"path":%q,"fstype":%q,"total":%d,"free":%d,"used":%d,"used_percent":%.2f}`,
device,
device,
disk.Path,
@ -344,81 +341,81 @@ func (s *SystemInfo) MarshalJSONTo(buf []byte) []byte {
disk.Total,
disk.Free,
disk.Used,
strconv.FormatFloat(float64(disk.UsedPercent), 'f', 2, 32),
))
disk.UsedPercent,
)
first = false
}
b.WriteRune('}')
b = append(b, '}')
} else {
b.WriteString("null")
b = append(b, "null"...)
}
// disks_io
b.WriteString(`,"disks_io":`)
b = append(b, `,"disks_io":`...)
if len(s.DisksIO) > 0 {
b.WriteString("{")
b = append(b, '{')
first := true
for name, usage := range s.DisksIO {
if !first {
b.WriteRune(',')
b = append(b, ',')
}
b.Write(fmt.Appendf(nil,
`"%s":{"name":%q,"read_bytes":%d,"write_bytes":%d,"read_speed":%s,"write_speed":%s,"iops":%d}`,
b = fmt.Appendf(b,
`"%s":{"name":%q,"read_bytes":%d,"write_bytes":%d,"read_speed":%.2f,"write_speed":%.2f,"iops":%d}`,
name,
name,
usage.ReadBytes,
usage.WriteBytes,
strconv.FormatFloat(usage.ReadSpeed, 'f', 2, 64),
strconv.FormatFloat(usage.WriteSpeed, 'f', 2, 64),
usage.ReadSpeed,
usage.WriteSpeed,
usage.Iops,
))
)
first = false
}
b.WriteRune('}')
b = append(b, '}')
} else {
b.WriteString("null")
b = append(b, "null"...)
}
// network
b.WriteString(`,"network":`)
b = append(b, `,"network":`...)
if s.Network != nil {
b.Write(fmt.Appendf(nil,
`{"bytes_sent":%d,"bytes_recv":%d,"upload_speed":%s,"download_speed":%s}`,
b = fmt.Appendf(b,
`{"bytes_sent":%d,"bytes_recv":%d,"upload_speed":%.2f,"download_speed":%.2f}`,
s.Network.BytesSent,
s.Network.BytesRecv,
strconv.FormatFloat(s.Network.UploadSpeed, 'f', 2, 64),
strconv.FormatFloat(s.Network.DownloadSpeed, 'f', 2, 64),
))
s.Network.UploadSpeed,
s.Network.DownloadSpeed,
)
} else {
b.WriteString("null")
b = append(b, "null"...)
}
// sensors
b.WriteString(`,"sensors":`)
b = append(b, `,"sensors":`...)
if len(s.Sensors) > 0 {
b.WriteRune('{')
b = append(b, '{')
first := true
for _, sensor := range s.Sensors {
if !first {
b.WriteRune(',')
b = append(b, ',')
}
b.Write(fmt.Appendf(nil,
`%q:{"name":%q,"temperature":%s,"high":%s,"critical":%s}`,
b = fmt.Appendf(b,
`"%s":{"name":%q,"temperature":%.2f,"high":%.2f,"critical":%.2f}`,
sensor.SensorKey,
sensor.SensorKey,
strconv.FormatFloat(float64(sensor.Temperature), 'f', 2, 32),
strconv.FormatFloat(float64(sensor.High), 'f', 2, 32),
strconv.FormatFloat(float64(sensor.Critical), 'f', 2, 32),
))
sensor.Temperature,
sensor.High,
sensor.Critical,
)
first = false
}
b.WriteRune('}')
b = append(b, '}')
} else {
b.WriteString("null")
b = append(b, "null"...)
}
b.WriteRune('}')
return b.Bytes()
b = append(b, '}')
return b
}
func (s *Sensors) UnmarshalJSON(data []byte) error {

View file

@ -49,6 +49,9 @@ func (p *DockerProvider) ShortName() string {
}
func (p *DockerProvider) IsExplicitOnly() bool {
if p.name == "" { // tests
return false
}
return p.name[len(p.name)-1] == '!'
}

View file

@ -15,7 +15,10 @@ import (
var testDockerLabelsYAML []byte
func TestParseDockerLabels(t *testing.T) {
var provider DockerProvider
provider := &DockerProvider{
name: "test",
dockerHost: "unix:///var/run/docker.sock",
}
labels := make(map[string]string)
expect.NoError(t, yaml.Unmarshal(testDockerLabelsYAML, &labels))

View file

@ -22,6 +22,7 @@ const (
func makeRoutes(cont *container.Summary, dockerHostIP ...string) route.Routes {
var p DockerProvider
var host string
if len(dockerHostIP) > 0 {
host = "tcp://" + dockerHostIP[0] + ":2375"
@ -30,6 +31,7 @@ func makeRoutes(cont *container.Summary, dockerHostIP ...string) route.Routes {
}
cont.ID = "test"
p.name = "test"
p.dockerHost = host
routes := expect.Must(p.routesFromContainerLabels(D.FromDocker(cont, host)))
for _, r := range routes {
r.Finalize()
@ -67,7 +69,7 @@ func TestApplyLabel(t *testing.T) {
Names: dummyNames,
Labels: map[string]string{
D.LabelAliases: "a,b",
D.LabelIdleTimeout: "",
D.LabelIdleTimeout: "10s",
D.LabelStopMethod: "stop",
D.LabelStopSignal: "SIGTERM",
D.LabelStopTimeout: "1h",
@ -109,8 +111,13 @@ func TestApplyLabel(t *testing.T) {
expect.Equal(t, a.Middlewares, middlewaresExpect)
expect.Equal(t, len(b.Middlewares), 0)
expect.Equal(t, a.Container.IdlewatcherConfig.IdleTimeout, 0)
expect.Equal(t, b.Container.IdlewatcherConfig.IdleTimeout, 0)
expect.NotNil(t, a.Container)
expect.NotNil(t, b.Container)
expect.NotNil(t, a.Container.IdlewatcherConfig)
expect.NotNil(t, b.Container.IdlewatcherConfig)
expect.Equal(t, a.Container.IdlewatcherConfig.IdleTimeout, 10*time.Second)
expect.Equal(t, b.Container.IdlewatcherConfig.IdleTimeout, 10*time.Second)
expect.Equal(t, a.Container.IdlewatcherConfig.StopTimeout, time.Hour)
expect.Equal(t, b.Container.IdlewatcherConfig.StopTimeout, time.Hour)
expect.Equal(t, a.Container.IdlewatcherConfig.StopMethod, "stop")

View file

@ -1,12 +1,14 @@
package rules
import (
"os"
"testing"
expect "github.com/yusing/go-proxy/internal/utils/testing"
)
func TestParseCommands(t *testing.T) {
tmpDir := t.TempDir()
tests := []struct {
name string
input string
@ -42,7 +44,7 @@ func TestParseCommands(t *testing.T) {
// serve tests
{
name: "serve_valid",
input: "serve /var/www",
input: "serve " + tmpDir,
wantErr: nil,
},
{
@ -55,6 +57,11 @@ func TestParseCommands(t *testing.T) {
input: "serve / / /",
wantErr: ErrInvalidArguments,
},
{
name: "serve_non_existent_path",
input: "serve " + tmpDir + "/non-existent",
wantErr: os.ErrNotExist,
},
// redirect tests
{
name: "redirect_valid",

View file

@ -45,7 +45,7 @@ func TestUnmarshal(t *testing.T) {
var s2 S
err := MapUnmarshalValidate(testStructSerialized, &s2)
expect.NoError(t, err)
expect.Values(t, s2, testStruct)
expect.Equal(t, s2, testStruct)
})
}
@ -65,15 +65,15 @@ func TestUnmarshalAnonymousField(t *testing.T) {
// t.Fatalf("anon %v, all %v", anon, all)
err := MapUnmarshalValidate(map[string]any{"a": 1, "b": 2, "c": 3}, &s)
expect.NoError(t, err)
expect.Values(t, s.A, 1)
expect.Values(t, s.B, 2)
expect.Values(t, s.C, 3)
expect.Equal(t, s.A, 1)
expect.Equal(t, s.B, 2)
expect.Equal(t, s.C, 3)
err = MapUnmarshalValidate(map[string]any{"a": 1, "b": 2, "c": 3}, &s2)
expect.NoError(t, err)
expect.Values(t, s2.A, 1)
expect.Values(t, s2.B, 2)
expect.Values(t, s2.C, 3)
expect.Equal(t, s2.A, 1)
expect.Equal(t, s2.B, 2)
expect.Equal(t, s2.C, 3)
}
func TestStringIntConvert(t *testing.T) {
@ -95,11 +95,11 @@ func TestStringIntConvert(t *testing.T) {
ok, err := ConvertString("127", field)
expect.True(t, ok)
expect.NoError(t, err)
expect.Values(t, field.Interface(), 127)
expect.Equal(t, field.Interface(), 127)
err = Convert(reflect.ValueOf(uint8(64)), field)
expect.NoError(t, err)
expect.Values(t, field.Interface(), 64)
expect.Equal(t, field.Interface(), 64)
})
}
}
@ -125,19 +125,19 @@ func TestConvertor(t *testing.T) {
m := new(testModel)
expect.NoError(t, MapUnmarshalValidate(map[string]any{"Test": "123"}, m))
expect.Values(t, m.Test.foo, 123)
expect.Values(t, m.Test.bar, "123")
expect.Equal(t, m.Test.foo, 123)
expect.Equal(t, m.Test.bar, "123")
})
t.Run("int_to_string", func(t *testing.T) {
m := new(testModel)
expect.NoError(t, MapUnmarshalValidate(map[string]any{"Test": "123"}, m))
expect.Values(t, m.Test.foo, 123)
expect.Values(t, m.Test.bar, "123")
expect.Equal(t, m.Test.foo, 123)
expect.Equal(t, m.Test.bar, "123")
expect.NoError(t, MapUnmarshalValidate(map[string]any{"Baz": 456}, m))
expect.Values(t, m.Baz, "456")
expect.Equal(t, m.Baz, "456")
})
t.Run("invalid", func(t *testing.T) {
@ -152,21 +152,21 @@ func TestStringToSlice(t *testing.T) {
convertible, err := ConvertString("a,b,c", reflect.ValueOf(&dst))
expect.True(t, convertible)
expect.NoError(t, err)
expect.Values(t, dst, []string{"a", "b", "c"})
expect.Equal(t, dst, []string{"a", "b", "c"})
})
t.Run("yaml-like", func(t *testing.T) {
dst := make([]string, 0)
convertible, err := ConvertString("- a\n- b\n- c", reflect.ValueOf(&dst))
expect.True(t, convertible)
expect.NoError(t, err)
expect.Values(t, dst, []string{"a", "b", "c"})
expect.Equal(t, dst, []string{"a", "b", "c"})
})
t.Run("single-line-yaml-like", func(t *testing.T) {
dst := make([]string, 0)
convertible, err := ConvertString("- a", reflect.ValueOf(&dst))
expect.True(t, convertible)
expect.NoError(t, err)
expect.Values(t, dst, []string{"a"})
expect.Equal(t, dst, []string{"a"})
})
}
@ -190,7 +190,7 @@ func TestStringToMap(t *testing.T) {
convertible, err := ConvertString(" a: b\n c: d", reflect.ValueOf(&dst))
expect.True(t, convertible)
expect.NoError(t, err)
expect.Values(t, dst, map[string]string{"a": "b", "c": "d"})
expect.Equal(t, dst, map[string]string{"a": "b", "c": "d"})
})
}
@ -218,8 +218,8 @@ func TestStringToStruct(t *testing.T) {
convertible, err := ConvertString(" A: a\n B: 123", reflect.ValueOf(&dst))
expect.True(t, convertible)
expect.NoError(t, err)
expect.Values(t, dst.A, "a")
expect.Values(t, dst.B, 123)
expect.Equal(t, dst.A, "a")
expect.Equal(t, dst.B, 123)
})
type T2 struct {

View file

@ -9,6 +9,13 @@ import (
"github.com/yusing/go-proxy/internal/utils/strutils/ansi"
)
// AppendDuration appends a duration to a buffer with the following format:
// - 1 ns
// - 1 ms
// - 1 seconds
// - 1 minutes and 1 seconds
// - 1 hours, 1 minutes and 1 seconds
// - 1 days, 1 hours and 1 minutes (ignore seconds if days >= 1)
func AppendDuration(d time.Duration, buf []byte) []byte {
if d < 0 {
buf = append(buf, '-')
@ -39,23 +46,37 @@ func AppendDuration(d time.Duration, buf []byte) []byte {
minutes := (totalSeconds % 3600) / 60
seconds := totalSeconds % 60
idxPartBeg := 0
if days > 0 {
buf = strconv.AppendInt(buf, days, 10)
buf = fmt.Appendf(buf, "day%s, ", Pluralize(days))
buf = fmt.Appendf(buf, " day%s, ", Pluralize(days))
}
if hours > 0 {
idxPartBeg = len(buf) - 2
buf = strconv.AppendInt(buf, hours, 10)
buf = fmt.Appendf(buf, "hour%s, ", Pluralize(hours))
buf = fmt.Appendf(buf, " hour%s, ", Pluralize(hours))
}
if minutes > 0 {
idxPartBeg = len(buf) - 2
buf = strconv.AppendInt(buf, minutes, 10)
buf = fmt.Appendf(buf, "minute%s, ", Pluralize(minutes))
buf = fmt.Appendf(buf, " minute%s, ", Pluralize(minutes))
}
if seconds > 0 && totalSeconds < 3600 {
idxPartBeg = len(buf) - 2
buf = strconv.AppendInt(buf, seconds, 10)
buf = fmt.Appendf(buf, "second%s, ", Pluralize(seconds))
buf = fmt.Appendf(buf, " second%s, ", Pluralize(seconds))
}
return buf[:len(buf)-2]
// remove last comma and space
buf = buf[:len(buf)-2]
if idxPartBeg > 0 && idxPartBeg < len(buf) {
// replace last part ', ' with ' and ' in-place, alloc-free
// ', ' is 2 bytes, ' and ' is 5 bytes, so we need to make room for 3 more bytes
tailLen := len(buf) - (idxPartBeg + 2)
buf = append(buf, "000"...) // append 3 bytes for ' and '
copy(buf[idxPartBeg+5:], buf[idxPartBeg+2:idxPartBeg+2+tailLen]) // shift tail right by 3
copy(buf[idxPartBeg:], " and ") // overwrite ', ' with ' and '
}
return buf
}
func FormatDuration(d time.Duration) string {

View file

@ -158,6 +158,16 @@ func TestFormatDuration(t *testing.T) {
duration: 1*24*time.Hour + 12*time.Hour,
expected: "1 day and 12 hours",
},
{
name: "days and hours and minutes",
duration: 1*24*time.Hour + 12*time.Hour + 30*time.Minute,
expected: "1 day, 12 hours and 30 minutes",
},
{
name: "days and hours and minutes and seconds (ignore seconds)",
duration: 1*24*time.Hour + 12*time.Hour + 30*time.Minute + 15*time.Second,
expected: "1 day, 12 hours and 30 minutes",
},
}
for _, tt := range tests {

View file

@ -45,7 +45,7 @@ func ErrorT[T error](t *testing.T, err error, msgAndArgs ...any) {
func Equal[T any](t *testing.T, got T, want T, msgAndArgs ...any) {
t.Helper()
require.Equal(t, want, got, msgAndArgs...)
require.EqualValues(t, want, got, msgAndArgs...)
}
func NotEqual[T any](t *testing.T, got T, want T, msgAndArgs ...any) {
@ -53,11 +53,6 @@ func NotEqual[T any](t *testing.T, got T, want T, msgAndArgs ...any) {
require.NotEqual(t, want, got, msgAndArgs...)
}
func Values(t *testing.T, got any, want any, msgAndArgs ...any) {
t.Helper()
require.EqualValues(t, want, got, msgAndArgs...)
}
func Contains[T any](t *testing.T, got T, wants []T, msgAndArgs ...any) {
t.Helper()
require.Contains(t, wants, got, msgAndArgs...)