From 5774737128001e17555cda74460258b5a9429132 Mon Sep 17 00:00:00 2001 From: Umputun Date: Thu, 23 May 2024 12:03:17 -0500 Subject: [PATCH] Handle default and concrete server match conflict #192 - Drop default server match if a concrete server match is found - Add test case to validate behavior --- app/discovery/discovery.go | 10 +++++ app/discovery/discovery_test.go | 67 +++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/app/discovery/discovery.go b/app/discovery/discovery.go index 688a9258..ac90f355 100644 --- a/app/discovery/discovery.go +++ b/app/discovery/discovery.go @@ -214,6 +214,16 @@ func (s *Service) Match(srv, src string) (res Matches) { } } + // if match returns both default and concrete server(s), drop default as we have a better match with concrete + if len(res.Routes) > 1 { + for i := range res.Routes { + if res.Routes[i].Mapper.Server == "*" || res.Routes[i].Mapper.Server == "" { + res.Routes = append(res.Routes[:i], res.Routes[i+1:]...) + break + } + } + } + return res } diff --git a/app/discovery/discovery_test.go b/app/discovery/discovery_test.go index 84161105..b675d0da 100644 --- a/app/discovery/discovery_test.go +++ b/app/discovery/discovery_test.go @@ -370,6 +370,73 @@ func TestService_MatchConflictRegex(t *testing.T) { } } +// https://github.com/umputun/reproxy/issues/192 +func TestService_Match192(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{ + { + Server: "*", + SrcMatch: *regexp.MustCompile("^/(.*)"), + Dst: "@temp https://site1.ru/", + ProviderID: PIFile, + }, + { + Server: "example1.ru", + SrcMatch: *regexp.MustCompile("^/(.*)"), + Dst: "@temp https://site2.ru/", + ProviderID: PIFile, + }, + { + Server: "example2.ru", + SrcMatch: *regexp.MustCompile("^/(.*)"), + Dst: "@temp https://site2.ru/", + 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 + }{ + {"example2.ru", "/something", Matches{MTProxy, []MatchedRoute{ + {Destination: "https://site2.ru/", Alive: true}}}}, + {"example1.ru", "/something", Matches{MTProxy, []MatchedRoute{ + {Destination: "https://site2.ru/", Alive: true}}}}, + {"example123.ru", "/something", Matches{MTProxy, []MatchedRoute{ + {Destination: "https://site1.ru/", 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 {