mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-21 16:01:22 +02:00
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
This commit is contained in:
@@ -54,7 +54,7 @@ func ParseLabels(labels map[string]string, aliases ...string) (types.LabelMap, e
|
|||||||
// Move deeper into the nested map
|
// Move deeper into the nested map
|
||||||
m, ok := currentMap[k].(types.LabelMap)
|
m, ok := currentMap[k].(types.LabelMap)
|
||||||
if !ok && currentMap[k] != "" {
|
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
|
continue
|
||||||
} else if !ok {
|
} else if !ok {
|
||||||
m = make(types.LabelMap)
|
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
|
// lbl is "proxy.X..." where X is alias or wildcard
|
||||||
rest := lbl[len(nsProxyDot):] // "X..." or "X.suffix"
|
rest := lbl[len(nsProxyDot):] // "X..." or "X.suffix"
|
||||||
dotIdx := strings.IndexByte(rest, '.')
|
alias, suffix, _ := strings.Cut(rest, ".")
|
||||||
var alias, suffix string
|
|
||||||
if dotIdx == -1 {
|
|
||||||
alias = rest
|
|
||||||
} else {
|
|
||||||
alias = rest[:dotIdx]
|
|
||||||
suffix = rest[dotIdx+1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
if alias == WildcardAlias {
|
if alias == WildcardAlias {
|
||||||
delete(labels, lbl)
|
delete(labels, lbl)
|
||||||
if suffix == "" || strings.Count(value, "\n") > 1 {
|
if suffix == "" || strings.Count(value, "\n") > 1 {
|
||||||
@@ -121,15 +113,10 @@ func ExpandWildcard(labels map[string]string, aliases ...string) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
rest := lbl[len(nsProxyDot):]
|
rest := lbl[len(nsProxyDot):]
|
||||||
dotIdx := strings.IndexByte(rest, '.')
|
alias, suffix, ok := strings.Cut(rest, ".")
|
||||||
if dotIdx == -1 {
|
if !ok || alias == "" || alias[0] == '#' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
alias := rest[:dotIdx]
|
|
||||||
if alias[0] == '#' {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
suffix := rest[dotIdx+1:]
|
|
||||||
|
|
||||||
idx, known := aliasSet[alias]
|
idx, known := aliasSet[alias]
|
||||||
if !known {
|
if !known {
|
||||||
|
|||||||
@@ -13,11 +13,9 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/yusing/godoxy/internal/common"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
. "github.com/yusing/godoxy/internal/entrypoint"
|
. "github.com/yusing/godoxy/internal/entrypoint"
|
||||||
entrypoint "github.com/yusing/godoxy/internal/entrypoint/types"
|
|
||||||
"github.com/yusing/godoxy/internal/route"
|
"github.com/yusing/godoxy/internal/route"
|
||||||
routeTypes "github.com/yusing/godoxy/internal/route/types"
|
routeTypes "github.com/yusing/godoxy/internal/route/types"
|
||||||
"github.com/yusing/godoxy/internal/types"
|
"github.com/yusing/godoxy/internal/types"
|
||||||
"github.com/yusing/goutils/task"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type noopResponseWriter struct {
|
type noopResponseWriter struct {
|
||||||
@@ -50,15 +48,13 @@ func (t noopTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkEntrypointReal(b *testing.B) {
|
func BenchmarkEntrypointReal(b *testing.B) {
|
||||||
task := task.GetTestTask(b)
|
ep := NewTestEntrypoint(b, nil)
|
||||||
ep := NewEntrypoint(task, nil)
|
|
||||||
req := http.Request{
|
req := http.Request{
|
||||||
Method: "GET",
|
Method: http.MethodGet,
|
||||||
URL: &url.URL{Path: "/", RawPath: "/"},
|
URL: &url.URL{Path: "/", RawPath: "/"},
|
||||||
Host: "test.domain.tld",
|
Host: "test.domain.tld",
|
||||||
}
|
}
|
||||||
ep.SetFindRouteDomains([]string{})
|
ep.SetFindRouteDomains([]string{})
|
||||||
entrypoint.SetCtx(task, ep)
|
|
||||||
|
|
||||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Length", "1")
|
w.Header().Set("Content-Length", "1")
|
||||||
@@ -85,7 +81,7 @@ func BenchmarkEntrypointReal(b *testing.B) {
|
|||||||
Alias: "test",
|
Alias: "test",
|
||||||
Scheme: routeTypes.SchemeHTTP,
|
Scheme: routeTypes.SchemeHTTP,
|
||||||
Host: host,
|
Host: host,
|
||||||
Port: route.Port{Proxy: portInt},
|
Port: route.Port{Listening: 1000, Proxy: portInt},
|
||||||
HealthCheck: types.HealthCheckConfig{Disable: true},
|
HealthCheck: types.HealthCheckConfig{Disable: true},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -94,7 +90,7 @@ func BenchmarkEntrypointReal(b *testing.B) {
|
|||||||
|
|
||||||
var w noopResponseWriter
|
var w noopResponseWriter
|
||||||
|
|
||||||
server, ok := ep.GetServer(common.ProxyHTTPAddr)
|
server, ok := ep.GetServer(":1000")
|
||||||
if !ok {
|
if !ok {
|
||||||
b.Fatal("server not found")
|
b.Fatal("server not found")
|
||||||
}
|
}
|
||||||
@@ -112,15 +108,13 @@ func BenchmarkEntrypointReal(b *testing.B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkEntrypoint(b *testing.B) {
|
func BenchmarkEntrypoint(b *testing.B) {
|
||||||
task := task.GetTestTask(b)
|
ep := NewTestEntrypoint(b, nil)
|
||||||
ep := NewEntrypoint(task, nil)
|
|
||||||
req := http.Request{
|
req := http.Request{
|
||||||
Method: "GET",
|
Method: http.MethodGet,
|
||||||
URL: &url.URL{Path: "/", RawPath: "/"},
|
URL: &url.URL{Path: "/", RawPath: "/"},
|
||||||
Host: "test.domain.tld",
|
Host: "test.domain.tld",
|
||||||
}
|
}
|
||||||
ep.SetFindRouteDomains([]string{})
|
ep.SetFindRouteDomains([]string{})
|
||||||
entrypoint.SetCtx(task, ep)
|
|
||||||
|
|
||||||
r, err := route.NewStartedTestRoute(b, &route.Route{
|
r, err := route.NewStartedTestRoute(b, &route.Route{
|
||||||
Alias: "test",
|
Alias: "test",
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ type Provider interface {
|
|||||||
|
|
||||||
// Status and monitoring
|
// Status and monitoring
|
||||||
ContainerStatus(ctx context.Context) (ContainerStatus, error)
|
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
|
// Cleanup
|
||||||
Close()
|
Close()
|
||||||
|
|||||||
@@ -303,7 +303,7 @@ curl "http://localhost:8080/api/uptime?period=1d&limit=20&offset=0&keyword=docke
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const ws = new WebSocket(
|
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) => {
|
ws.onmessage = (event) => {
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ package serialization_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/yusing/godoxy/internal/serialization"
|
"github.com/yusing/godoxy/internal/serialization"
|
||||||
gperr "github.com/yusing/goutils/errs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestStruct struct {
|
type TestStruct struct {
|
||||||
@@ -14,18 +15,17 @@ type TestStruct struct {
|
|||||||
Value2 int `json:"value2"`
|
Value2 int `json:"value2"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TestStruct) Validate() gperr.Error {
|
func (t *TestStruct) Validate() error {
|
||||||
if t.Value == "" {
|
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) {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGinBinding(t *testing.T) {
|
func TestGinBinding(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
input string
|
input string
|
||||||
@@ -40,7 +40,7 @@ func TestGinBinding(t *testing.T) {
|
|||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
var dst TestStruct
|
var dst TestStruct
|
||||||
body := bytes.NewBufferString(tt.input)
|
body := bytes.NewBufferString(tt.input)
|
||||||
req := httptest.NewRequest("POST", "/", body)
|
req := httptest.NewRequest(http.MethodPost, "/", body)
|
||||||
err := serialization.GinJSONBinding{}.Bind(req, &dst)
|
err := serialization.GinJSONBinding{}.Bind(req, &dst)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("%s: Bind() error = %v, wantErr %v", tt.name, err, tt.wantErr)
|
t.Errorf("%s: Bind() error = %v, wantErr %v", tt.name, err, tt.wantErr)
|
||||||
|
|||||||
@@ -1,24 +1,23 @@
|
|||||||
package serialization
|
package serialization
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
gperr "github.com/yusing/goutils/errs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Test cases for when *T implements CustomValidator but T is passed in
|
// Test cases for when *T implements CustomValidator but T is passed in
|
||||||
type CustomValidatingInt int
|
type CustomValidatingInt int
|
||||||
|
|
||||||
func (c *CustomValidatingInt) Validate() gperr.Error {
|
func (c *CustomValidatingInt) Validate() error {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return gperr.New("pointer int cannot be nil")
|
return errors.New("pointer int cannot be nil")
|
||||||
}
|
}
|
||||||
if *c <= 0 {
|
if *c <= 0 {
|
||||||
return gperr.New("int must be positive")
|
return errors.New("int must be positive")
|
||||||
}
|
}
|
||||||
if *c > 100 {
|
if *c > 100 {
|
||||||
return gperr.New("int must be <= 100")
|
return errors.New("int must be <= 100")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -26,12 +25,12 @@ func (c *CustomValidatingInt) Validate() gperr.Error {
|
|||||||
// Test cases for when T implements CustomValidator but *T is passed in
|
// Test cases for when T implements CustomValidator but *T is passed in
|
||||||
type CustomValidatingFloat float64
|
type CustomValidatingFloat float64
|
||||||
|
|
||||||
func (c CustomValidatingFloat) Validate() gperr.Error {
|
func (c CustomValidatingFloat) Validate() error {
|
||||||
if c < 0 {
|
if c < 0 {
|
||||||
return gperr.New("float must be non-negative")
|
return errors.New("float must be non-negative")
|
||||||
}
|
}
|
||||||
if c > 1000 {
|
if c > 1000 {
|
||||||
return gperr.New("float must be <= 1000")
|
return errors.New("float must be <= 1000")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,22 @@
|
|||||||
package serialization
|
package serialization
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
gperr "github.com/yusing/goutils/errs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type CustomValidatingPointerString string
|
type CustomValidatingPointerString string
|
||||||
|
|
||||||
func (c *CustomValidatingPointerString) Validate() gperr.Error {
|
func (c *CustomValidatingPointerString) Validate() error {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return gperr.New("pointer string cannot be nil")
|
return errors.New("pointer string cannot be nil")
|
||||||
}
|
}
|
||||||
if *c == "" {
|
if *c == "" {
|
||||||
return gperr.New("string cannot be empty")
|
return errors.New("string cannot be empty")
|
||||||
}
|
}
|
||||||
if len(*c) < 2 {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
package serialization
|
package serialization
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
gperr "github.com/yusing/goutils/errs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type CustomValidatingString string
|
type CustomValidatingString string
|
||||||
|
|
||||||
func (c CustomValidatingString) Validate() gperr.Error {
|
func (c CustomValidatingString) Validate() error {
|
||||||
if c == "" {
|
if c == "" {
|
||||||
return gperr.New("string cannot be empty")
|
return errors.New("string cannot be empty")
|
||||||
}
|
}
|
||||||
if len(c) < 2 {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,24 @@
|
|||||||
package serialization
|
package serialization
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
gperr "github.com/yusing/goutils/errs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type CustomValidatingPointerStruct struct {
|
type CustomValidatingPointerStruct struct {
|
||||||
Value string
|
Value string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CustomValidatingPointerStruct) Validate() gperr.Error {
|
func (c *CustomValidatingPointerStruct) Validate() error {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return gperr.New("pointer struct cannot be nil")
|
return errors.New("pointer struct cannot be nil")
|
||||||
}
|
}
|
||||||
if c.Value == "" {
|
if c.Value == "" {
|
||||||
return gperr.New("value cannot be empty")
|
return errors.New("value cannot be empty")
|
||||||
}
|
}
|
||||||
if len(c.Value) < 3 {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
package serialization
|
package serialization
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
gperr "github.com/yusing/goutils/errs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type CustomValidatingStruct struct {
|
type CustomValidatingStruct struct {
|
||||||
Value string
|
Value string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c CustomValidatingStruct) Validate() gperr.Error {
|
func (c CustomValidatingStruct) Validate() error {
|
||||||
if c.Value == "" {
|
if c.Value == "" {
|
||||||
return gperr.New("value cannot be empty")
|
return errors.New("value cannot be empty")
|
||||||
}
|
}
|
||||||
if len(c.Value) < 3 {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ Alias to `events.Event` for convenience.
|
|||||||
type Watcher interface {
|
type Watcher interface {
|
||||||
// Events returns channels for receiving events and errors.
|
// Events returns channels for receiving events and errors.
|
||||||
// The channels are closed when the context is cancelled.
|
// 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)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user