From 1579f490c06ed9d7e9c816779b634dfcd18aa45c Mon Sep 17 00:00:00 2001 From: yusing Date: Tue, 10 Feb 2026 16:59:19 +0800 Subject: [PATCH] refactor: replace gperr with standard errors package and simplify string parsing - Replace gperr.Error return types with standard error across test files - Replace gperr.New with errors.New in validation and serialization tests - Update API documentation in README files to use error instead of gperr.Error - Simplify string parsing using strings.Cut in docker/label.go - Update benchmarks to use NewTestEntrypoint and remove task package dependency --- internal/docker/label.go | 21 ++++--------------- .../entrypoint/entrypoint_benchmark_test.go | 18 ++++++---------- internal/idlewatcher/provider/README.md | 2 +- internal/metrics/uptime/README.md | 2 +- internal/serialization/gin_binding_test.go | 12 +++++------ .../serialization/validation_mismatch_test.go | 17 +++++++-------- .../validation_string_ptr_test.go | 11 +++++----- .../serialization/validation_string_test.go | 9 ++++---- .../validation_struct_ptr_test.go | 11 +++++----- .../serialization/validation_struct_test.go | 9 ++++---- internal/watcher/README.md | 2 +- 11 files changed, 45 insertions(+), 69 deletions(-) diff --git a/internal/docker/label.go b/internal/docker/label.go index 4ef0d367..d5800ca5 100644 --- a/internal/docker/label.go +++ b/internal/docker/label.go @@ -54,7 +54,7 @@ func ParseLabels(labels map[string]string, aliases ...string) (types.LabelMap, e // Move deeper into the nested map m, ok := currentMap[k].(types.LabelMap) if !ok && currentMap[k] != "" { - errs.Add(gperr.Errorf("expect mapping, got %T", currentMap[k]).Subject(lbl)) + errs.AddSubject(fmt.Errorf("expect mapping, got %T", currentMap[k]), lbl) continue } else if !ok { m = make(types.LabelMap) @@ -83,15 +83,7 @@ func ExpandWildcard(labels map[string]string, aliases ...string) { } // lbl is "proxy.X..." where X is alias or wildcard rest := lbl[len(nsProxyDot):] // "X..." or "X.suffix" - dotIdx := strings.IndexByte(rest, '.') - var alias, suffix string - if dotIdx == -1 { - alias = rest - } else { - alias = rest[:dotIdx] - suffix = rest[dotIdx+1:] - } - + alias, suffix, _ := strings.Cut(rest, ".") if alias == WildcardAlias { delete(labels, lbl) if suffix == "" || strings.Count(value, "\n") > 1 { @@ -121,15 +113,10 @@ func ExpandWildcard(labels map[string]string, aliases ...string) { continue } rest := lbl[len(nsProxyDot):] - dotIdx := strings.IndexByte(rest, '.') - if dotIdx == -1 { + alias, suffix, ok := strings.Cut(rest, ".") + if !ok || alias == "" || alias[0] == '#' { continue } - alias := rest[:dotIdx] - if alias[0] == '#' { - continue - } - suffix := rest[dotIdx+1:] idx, known := aliasSet[alias] if !known { diff --git a/internal/entrypoint/entrypoint_benchmark_test.go b/internal/entrypoint/entrypoint_benchmark_test.go index 2e519e4d..5cb1bc6f 100644 --- a/internal/entrypoint/entrypoint_benchmark_test.go +++ b/internal/entrypoint/entrypoint_benchmark_test.go @@ -13,11 +13,9 @@ import ( "github.com/stretchr/testify/require" "github.com/yusing/godoxy/internal/common" . "github.com/yusing/godoxy/internal/entrypoint" - entrypoint "github.com/yusing/godoxy/internal/entrypoint/types" "github.com/yusing/godoxy/internal/route" routeTypes "github.com/yusing/godoxy/internal/route/types" "github.com/yusing/godoxy/internal/types" - "github.com/yusing/goutils/task" ) type noopResponseWriter struct { @@ -50,15 +48,13 @@ func (t noopTransport) RoundTrip(req *http.Request) (*http.Response, error) { } func BenchmarkEntrypointReal(b *testing.B) { - task := task.GetTestTask(b) - ep := NewEntrypoint(task, nil) + ep := NewTestEntrypoint(b, nil) req := http.Request{ - Method: "GET", + Method: http.MethodGet, URL: &url.URL{Path: "/", RawPath: "/"}, Host: "test.domain.tld", } ep.SetFindRouteDomains([]string{}) - entrypoint.SetCtx(task, ep) srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Length", "1") @@ -85,7 +81,7 @@ func BenchmarkEntrypointReal(b *testing.B) { Alias: "test", Scheme: routeTypes.SchemeHTTP, Host: host, - Port: route.Port{Proxy: portInt}, + Port: route.Port{Listening: 1000, Proxy: portInt}, HealthCheck: types.HealthCheckConfig{Disable: true}, }) @@ -94,7 +90,7 @@ func BenchmarkEntrypointReal(b *testing.B) { var w noopResponseWriter - server, ok := ep.GetServer(common.ProxyHTTPAddr) + server, ok := ep.GetServer(":1000") if !ok { b.Fatal("server not found") } @@ -112,15 +108,13 @@ func BenchmarkEntrypointReal(b *testing.B) { } func BenchmarkEntrypoint(b *testing.B) { - task := task.GetTestTask(b) - ep := NewEntrypoint(task, nil) + ep := NewTestEntrypoint(b, nil) req := http.Request{ - Method: "GET", + Method: http.MethodGet, URL: &url.URL{Path: "/", RawPath: "/"}, Host: "test.domain.tld", } ep.SetFindRouteDomains([]string{}) - entrypoint.SetCtx(task, ep) r, err := route.NewStartedTestRoute(b, &route.Route{ Alias: "test", diff --git a/internal/idlewatcher/provider/README.md b/internal/idlewatcher/provider/README.md index 5224098e..fb42ba67 100644 --- a/internal/idlewatcher/provider/README.md +++ b/internal/idlewatcher/provider/README.md @@ -36,7 +36,7 @@ type Provider interface { // Status and monitoring ContainerStatus(ctx context.Context) (ContainerStatus, error) - Watch(ctx context.Context) (eventCh <-chan events.Event, errCh <-chan gperr.Error) + Watch(ctx context.Context) (eventCh <-chan events.Event, errCh <-chan error) // Cleanup Close() diff --git a/internal/metrics/uptime/README.md b/internal/metrics/uptime/README.md index 8c748c14..65e7bbd0 100644 --- a/internal/metrics/uptime/README.md +++ b/internal/metrics/uptime/README.md @@ -303,7 +303,7 @@ curl "http://localhost:8080/api/uptime?period=1d&limit=20&offset=0&keyword=docke ```javascript const ws = new WebSocket( - "ws://localhost:8080/api/uptime?period=1m&interval=5s" + "ws://localhost:8080/api/uptime?period=1m&interval=5s", ); ws.onmessage = (event) => { diff --git a/internal/serialization/gin_binding_test.go b/internal/serialization/gin_binding_test.go index d7f8830e..62193da2 100644 --- a/internal/serialization/gin_binding_test.go +++ b/internal/serialization/gin_binding_test.go @@ -2,11 +2,12 @@ package serialization_test import ( "bytes" + "errors" + "net/http" "net/http/httptest" "testing" "github.com/yusing/godoxy/internal/serialization" - gperr "github.com/yusing/goutils/errs" ) type TestStruct struct { @@ -14,18 +15,17 @@ type TestStruct struct { Value2 int `json:"value2"` } -func (t *TestStruct) Validate() gperr.Error { +func (t *TestStruct) Validate() error { if t.Value == "" { - return gperr.New("value is required") + return errors.New("value is required") } if t.Value2 != 0 && (t.Value2 < 5 || t.Value2 > 10) { - return gperr.New("value2 must be between 5 and 10") + return errors.New("value2 must be between 5 and 10") } return nil } func TestGinBinding(t *testing.T) { - tests := []struct { name string input string @@ -40,7 +40,7 @@ func TestGinBinding(t *testing.T) { t.Run(tt.name, func(t *testing.T) { var dst TestStruct body := bytes.NewBufferString(tt.input) - req := httptest.NewRequest("POST", "/", body) + req := httptest.NewRequest(http.MethodPost, "/", body) err := serialization.GinJSONBinding{}.Bind(req, &dst) if (err != nil) != tt.wantErr { t.Errorf("%s: Bind() error = %v, wantErr %v", tt.name, err, tt.wantErr) diff --git a/internal/serialization/validation_mismatch_test.go b/internal/serialization/validation_mismatch_test.go index 15aad4ca..a46f65a8 100644 --- a/internal/serialization/validation_mismatch_test.go +++ b/internal/serialization/validation_mismatch_test.go @@ -1,24 +1,23 @@ package serialization import ( + "errors" "reflect" "testing" - - gperr "github.com/yusing/goutils/errs" ) // Test cases for when *T implements CustomValidator but T is passed in type CustomValidatingInt int -func (c *CustomValidatingInt) Validate() gperr.Error { +func (c *CustomValidatingInt) Validate() error { if c == nil { - return gperr.New("pointer int cannot be nil") + return errors.New("pointer int cannot be nil") } if *c <= 0 { - return gperr.New("int must be positive") + return errors.New("int must be positive") } if *c > 100 { - return gperr.New("int must be <= 100") + return errors.New("int must be <= 100") } return nil } @@ -26,12 +25,12 @@ func (c *CustomValidatingInt) Validate() gperr.Error { // Test cases for when T implements CustomValidator but *T is passed in type CustomValidatingFloat float64 -func (c CustomValidatingFloat) Validate() gperr.Error { +func (c CustomValidatingFloat) Validate() error { if c < 0 { - return gperr.New("float must be non-negative") + return errors.New("float must be non-negative") } if c > 1000 { - return gperr.New("float must be <= 1000") + return errors.New("float must be <= 1000") } return nil } diff --git a/internal/serialization/validation_string_ptr_test.go b/internal/serialization/validation_string_ptr_test.go index 1de98ecc..4d6a58f2 100644 --- a/internal/serialization/validation_string_ptr_test.go +++ b/internal/serialization/validation_string_ptr_test.go @@ -1,23 +1,22 @@ package serialization import ( + "errors" "reflect" "testing" - - gperr "github.com/yusing/goutils/errs" ) type CustomValidatingPointerString string -func (c *CustomValidatingPointerString) Validate() gperr.Error { +func (c *CustomValidatingPointerString) Validate() error { if c == nil { - return gperr.New("pointer string cannot be nil") + return errors.New("pointer string cannot be nil") } if *c == "" { - return gperr.New("string cannot be empty") + return errors.New("string cannot be empty") } if len(*c) < 2 { - return gperr.New("string must be at least 2 characters") + return errors.New("string must be at least 2 characters") } return nil } diff --git a/internal/serialization/validation_string_test.go b/internal/serialization/validation_string_test.go index b432492b..89e3773e 100644 --- a/internal/serialization/validation_string_test.go +++ b/internal/serialization/validation_string_test.go @@ -1,20 +1,19 @@ package serialization import ( + "errors" "reflect" "testing" - - gperr "github.com/yusing/goutils/errs" ) type CustomValidatingString string -func (c CustomValidatingString) Validate() gperr.Error { +func (c CustomValidatingString) Validate() error { if c == "" { - return gperr.New("string cannot be empty") + return errors.New("string cannot be empty") } if len(c) < 2 { - return gperr.New("string must be at least 2 characters") + return errors.New("string must be at least 2 characters") } return nil } diff --git a/internal/serialization/validation_struct_ptr_test.go b/internal/serialization/validation_struct_ptr_test.go index 6d09646b..1924a392 100644 --- a/internal/serialization/validation_struct_ptr_test.go +++ b/internal/serialization/validation_struct_ptr_test.go @@ -1,25 +1,24 @@ package serialization import ( + "errors" "reflect" "testing" - - gperr "github.com/yusing/goutils/errs" ) type CustomValidatingPointerStruct struct { Value string } -func (c *CustomValidatingPointerStruct) Validate() gperr.Error { +func (c *CustomValidatingPointerStruct) Validate() error { if c == nil { - return gperr.New("pointer struct cannot be nil") + return errors.New("pointer struct cannot be nil") } if c.Value == "" { - return gperr.New("value cannot be empty") + return errors.New("value cannot be empty") } if len(c.Value) < 3 { - return gperr.New("value must be at least 3 characters") + return errors.New("value must be at least 3 characters") } return nil } diff --git a/internal/serialization/validation_struct_test.go b/internal/serialization/validation_struct_test.go index 37fef26e..1c22aa1f 100644 --- a/internal/serialization/validation_struct_test.go +++ b/internal/serialization/validation_struct_test.go @@ -1,22 +1,21 @@ package serialization import ( + "errors" "reflect" "testing" - - gperr "github.com/yusing/goutils/errs" ) type CustomValidatingStruct struct { Value string } -func (c CustomValidatingStruct) Validate() gperr.Error { +func (c CustomValidatingStruct) Validate() error { if c.Value == "" { - return gperr.New("value cannot be empty") + return errors.New("value cannot be empty") } if len(c.Value) < 3 { - return gperr.New("value must be at least 3 characters") + return errors.New("value must be at least 3 characters") } return nil } diff --git a/internal/watcher/README.md b/internal/watcher/README.md index a62bb055..29efd8f2 100644 --- a/internal/watcher/README.md +++ b/internal/watcher/README.md @@ -40,7 +40,7 @@ Alias to `events.Event` for convenience. type Watcher interface { // Events returns channels for receiving events and errors. // The channels are closed when the context is cancelled. - Events(ctx context.Context) (<-chan Event, <-chan gperr.Error) + Events(ctx context.Context) (<-chan Event, <-chan error) } ```