From 503f0b6dca24a2e967c6591ccea40610c0e1871c Mon Sep 17 00:00:00 2001 From: Umputun Date: Tue, 8 Jun 2021 15:32:35 -0500 Subject: [PATCH] drop regex group in source priority sorting #89 --- app/discovery/discovery.go | 10 ++++-- app/discovery/discovery_test.go | 61 ++++++++++++++++++++++++++++++--- 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/app/discovery/discovery.go b/app/discovery/discovery.go index 172cc085..603cde82 100644 --- a/app/discovery/discovery.go +++ b/app/discovery/discovery.go @@ -74,6 +74,8 @@ const ( PIConsulCatalog ProviderID = "consul-catalog" ) +var reGroup = regexp.MustCompile(`(^.*)/\(.*\)`) // capture regex group lil (anything) from src like /blah/foo/(.*) + // MatchType defines the type of mapper (rule) type MatchType int @@ -327,9 +329,13 @@ func (s *Service) mergeLists() (res []URLMapper) { // sort rules to make assets last and prioritize longer rules first sort.Slice(res, func(i, j int) bool { + + src1 := reGroup.ReplaceAllString(res[i].SrcMatch.String(), "$1") + src2 := reGroup.ReplaceAllString(res[j].SrcMatch.String(), "$1") + // sort by len first, to make longer matches first - if len(res[i].SrcMatch.String()) != len(res[j].SrcMatch.String()) { - return len(res[i].SrcMatch.String()) > len(res[j].SrcMatch.String()) + if len(src1) != len(src2) { + return len(src1) > len(src2) } // if len identical sort by SrcMatch string to keep same SrcMatch grouped together return res[i].SrcMatch.String() < res[j].SrcMatch.String() diff --git a/app/discovery/discovery_test.go b/app/discovery/discovery_test.go index 933d3b30..a4522051 100644 --- a/app/discovery/discovery_test.go +++ b/app/discovery/discovery_test.go @@ -62,10 +62,10 @@ func TestService_Run(t *testing.T) { assert.Equal(t, context.DeadlineExceeded, err) mappers := svc.Mappers() assert.Equal(t, 3, len(mappers)) - assert.Equal(t, PIFile, mappers[0].ProviderID) - assert.Equal(t, "*", mappers[0].Server) - assert.Equal(t, "^/api/svc1/(.*)", mappers[0].SrcMatch.String()) - assert.Equal(t, "http://127.0.0.1:8080/blah1/$1", mappers[0].Dst) + assert.Equal(t, PIDocker, mappers[0].ProviderID) + assert.Equal(t, "localhost", mappers[0].Server) + assert.Equal(t, "/api/svc3/xyz", mappers[0].SrcMatch.String()) + assert.Equal(t, "http://127.0.0.3:8080/blah3/xyz", mappers[0].Dst) assert.Equal(t, 1, len(p1.EventsCalls())) assert.Equal(t, 1, len(p2.EventsCalls())) @@ -173,6 +173,59 @@ func TestService_Match(t *testing.T) { } } +func TestService_MatchConflictRegex(t *testing.T) { + p1 := &ProviderMock{ + EventsFunc: func(ctx context.Context) <-chan ProviderID { + res := make(chan ProviderID, 1) + res <- PIFile + return res + }, + ListFunc: func() ([]URLMapper, error) { + return []URLMapper{ + {SrcMatch: *regexp.MustCompile("^/api/svc1/(.*)"), Dst: "http://127.0.0.1:8080/blah/$1", ProviderID: PIFile}, + {SrcMatch: *regexp.MustCompile("^/api/svc1/cat"), Dst: "http://127.0.0.2:8080/cat", ProviderID: PIFile}, + {SrcMatch: *regexp.MustCompile("^/api/svc1/abcd"), Dst: "http://127.0.0.3:8080/abcd", ProviderID: PIFile}, + }, nil + }, + } + + svc := NewService([]Provider{p1}, time.Millisecond*100) + ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) + defer cancel() + + err := svc.Run(ctx) + require.Error(t, err) + assert.Equal(t, context.DeadlineExceeded, err) + assert.Equal(t, 3, len(svc.Mappers())) + + tbl := []struct { + server, src string + res Matches + }{ + {"example.com", "/api/svc1/xyz/something", Matches{MTProxy, []MatchedRoute{ + {Destination: "http://127.0.0.1:8080/blah/xyz/something", Alive: true}}}}, + {"example.com", "/api/svc1/something", Matches{MTProxy, []MatchedRoute{ + {Destination: "http://127.0.0.1:8080/blah/something", Alive: true}}}}, + {"example.com", "/api/svc1/cat", Matches{MTProxy, []MatchedRoute{ + {Destination: "http://127.0.0.2:8080/cat", Alive: true}}}}, + {"example.com", "/api/svc1/abcd", Matches{MTProxy, []MatchedRoute{ + {Destination: "http://127.0.0.3:8080/abcd", Alive: true}}}}, + } + + for i, tt := range tbl { + tt := tt + t.Run(strconv.Itoa(i), func(t *testing.T) { + res := svc.Match(tt.server, tt.src) + require.Equal(t, len(tt.res.Routes), len(res.Routes), res.Routes) + for i := 0; i < len(res.Routes); i++ { + assert.Equal(t, tt.res.Routes[i].Alive, res.Routes[i].Alive) + assert.Equal(t, tt.res.Routes[i].Destination, res.Routes[i].Destination) + } + assert.Equal(t, tt.res.MatchType, res.MatchType) + }) + } +} + func TestService_Servers(t *testing.T) { p1 := &ProviderMock{ EventsFunc: func(ctx context.Context) <-chan ProviderID {