From 4d4f8427026946c5e5e6d91a23680c3452fa2f85 Mon Sep 17 00:00:00 2001 From: Asim Date: Sat, 23 Apr 2016 20:15:01 +0100 Subject: [PATCH 1/5] Change SelectFilter to Filter --- examples/client/dc_filter/dc_filter.go | 2 +- selector/options.go | 6 +++--- selector/selector.go | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/client/dc_filter/dc_filter.go b/examples/client/dc_filter/dc_filter.go index 49d52a0e..9b018281 100644 --- a/examples/client/dc_filter/dc_filter.go +++ b/examples/client/dc_filter/dc_filter.go @@ -41,7 +41,7 @@ func (dc *dcWrapper) Call(ctx context.Context, req client.Request, rsp interface } callOptions := append(opts, client.WithSelectOption( - selector.Filter(filter), + selector.WithFilter(filter), )) fmt.Printf("[DC Wrapper] filtering for datacenter %s\n", md["datacenter"]) diff --git a/selector/options.go b/selector/options.go index 13973489..a9fe796d 100644 --- a/selector/options.go +++ b/selector/options.go @@ -15,7 +15,7 @@ type Options struct { } type SelectOptions struct { - Filters []SelectFilter + Filters []Filter // Other options for implementations of the interface // can be stored in a context @@ -35,9 +35,9 @@ func Registry(r registry.Registry) Option { } } -// Filter adds a filter function to the list of filters +// WithFilter adds a filter function to the list of filters // used during the Select call. -func Filter(fn SelectFilter) SelectOption { +func WithFilter(fn Filter) SelectOption { return func(o *SelectOptions) { o.Filters = append(o.Filters, fn) } diff --git a/selector/selector.go b/selector/selector.go index 551b0a41..42ccd300 100644 --- a/selector/selector.go +++ b/selector/selector.go @@ -82,8 +82,8 @@ type Selector interface { // based on the selector's algorithm type Next func() (*registry.Node, error) -// SelectFilter is used to filter a service during the selection process -type SelectFilter func([]*registry.Service) []*registry.Service +// Filter is used to filter a service during the selection process +type Filter func([]*registry.Service) []*registry.Service var ( DefaultSelector = newRandomSelector() From 7c3ce60ce6ba039b1525f97e6d8f4a14550ec7da Mon Sep 17 00:00:00 2001 From: Asim Date: Sat, 23 Apr 2016 20:57:46 +0100 Subject: [PATCH 2/5] Add label and version filters --- selector/filter.go | 54 ++++++++++++++ selector/filter_test.go | 158 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 212 insertions(+) create mode 100644 selector/filter.go create mode 100644 selector/filter_test.go diff --git a/selector/filter.go b/selector/filter.go new file mode 100644 index 00000000..0a644b0c --- /dev/null +++ b/selector/filter.go @@ -0,0 +1,54 @@ +package selector + +import ( + "github.com/micro/go-micro/registry" +) + +// LabelFilter is a label based Select Filter which will +// only return services with the label specified. +func LabelFilter(key, val string) Filter { + return func(old []*registry.Service) []*registry.Service { + var services []*registry.Service + + for _, service := range old { + serv := new(registry.Service) + var nodes []*registry.Node + + for _, node := range service.Nodes { + if node.Metadata == nil { + continue + } + + if node.Metadata[key] == val { + nodes = append(nodes, node) + } + } + + // only add service if there's some nodes + if len(nodes) > 0 { + // copy + *serv = *service + serv.Nodes = nodes + services = append(services, serv) + } + } + + return services + } +} + +// VersionFilter is a version based Select Filter which will +// only return services with the version specified. +func VersionFilter(version string) Filter { + return func(old []*registry.Service) []*registry.Service { + var services []*registry.Service + + for _, service := range old { + if service.Version == version { + services = append(services, service) + } + } + + return services + } +} diff --git a/selector/filter_test.go b/selector/filter_test.go new file mode 100644 index 00000000..a77ca645 --- /dev/null +++ b/selector/filter_test.go @@ -0,0 +1,158 @@ +package selector + +import ( + "testing" + + "github.com/micro/go-micro/registry" +) + +func TestLabelFilter(t *testing.T) { + testData := []struct { + services []*registry.Service + label [2]string + count int + }{ + { + services: []*registry.Service{ + ®istry.Service{ + Name: "test", + Version: "1.0.0", + Nodes: []*registry.Node{ + ®istry.Node{ + Id: "test-1", + Address: "localhost", + Metadata: map[string]string{ + "foo": "bar", + }, + }, + }, + }, + ®istry.Service{ + Name: "test", + Version: "1.1.0", + Nodes: []*registry.Node{ + ®istry.Node{ + Id: "test-2", + Address: "localhost", + Metadata: map[string]string{ + "foo": "baz", + }, + }, + }, + }, + }, + label: [2]string{"foo", "bar"}, + count: 1, + }, + { + services: []*registry.Service{ + ®istry.Service{ + Name: "test", + Version: "1.0.0", + Nodes: []*registry.Node{ + ®istry.Node{ + Id: "test-1", + Address: "localhost", + }, + }, + }, + ®istry.Service{ + Name: "test", + Version: "1.1.0", + Nodes: []*registry.Node{ + ®istry.Node{ + Id: "test-2", + Address: "localhost", + }, + }, + }, + }, + label: [2]string{"foo", "bar"}, + count: 0, + }, + } + + for _, data := range testData { + filter := LabelFilter(data.label[0], data.label[1]) + services := filter(data.services) + + if len(services) != data.count { + t.Fatalf("Expected %d services, got %d", data.count, len(services)) + } + + for _, service := range services { + var seen bool + + for _, node := range service.Nodes { + if node.Metadata[data.label[0]] != data.label[1] { + t.Fatal("Expected %s=%s but got %s=%s for service %+v node %+v", + data.label[0], data.label[1], data.label[0], node.Metadata[data.label[0]], service, node) + } + seen = true + } + + if !seen { + t.Fatalf("Expected node for %s=%s but saw none; results %+v", data.label[0], data.label[1], service) + } + } + } +} + +func TestVersionFilter(t *testing.T) { + testData := []struct { + services []*registry.Service + version string + count int + }{ + { + services: []*registry.Service{ + ®istry.Service{ + Name: "test", + Version: "1.0.0", + }, + ®istry.Service{ + Name: "test", + Version: "1.1.0", + }, + }, + version: "1.0.0", + count: 1, + }, + { + services: []*registry.Service{ + ®istry.Service{ + Name: "test", + Version: "1.0.0", + }, + ®istry.Service{ + Name: "test", + Version: "1.1.0", + }, + }, + version: "2.0.0", + count: 0, + }, + } + + for _, data := range testData { + filter := VersionFilter(data.version) + services := filter(data.services) + + if len(services) != data.count { + t.Fatalf("Expected %d services, got %d", data.count, len(services)) + } + + var seen bool + + for _, service := range services { + if service.Version != data.version { + t.Fatalf("Expected version %s, got %s", data.version, service.Version) + } + seen = true + } + + if seen == false && data.count > 0 { + t.Fatalf("Expected %d services but seen is %t; result %+v", data.count, seen, services) + } + } +} From febe87dfb8148b0580a7effe43d66c4b880adeae Mon Sep 17 00:00:00 2001 From: Asim Date: Sat, 23 Apr 2016 21:09:48 +0100 Subject: [PATCH 3/5] Switch around method names --- selector/filter.go | 8 ++++---- selector/filter_test.go | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/selector/filter.go b/selector/filter.go index 0a644b0c..0547b59e 100644 --- a/selector/filter.go +++ b/selector/filter.go @@ -4,9 +4,9 @@ import ( "github.com/micro/go-micro/registry" ) -// LabelFilter is a label based Select Filter which will +// FilterLabel is a label based Select Filter which will // only return services with the label specified. -func LabelFilter(key, val string) Filter { +func FilterLabel(key, val string) Filter { return func(old []*registry.Service) []*registry.Service { var services []*registry.Service @@ -37,9 +37,9 @@ func LabelFilter(key, val string) Filter { } } -// VersionFilter is a version based Select Filter which will +// FilterVersion is a version based Select Filter which will // only return services with the version specified. -func VersionFilter(version string) Filter { +func FilterVersion(version string) Filter { return func(old []*registry.Service) []*registry.Service { var services []*registry.Service diff --git a/selector/filter_test.go b/selector/filter_test.go index a77ca645..793c00f9 100644 --- a/selector/filter_test.go +++ b/selector/filter_test.go @@ -6,7 +6,7 @@ import ( "github.com/micro/go-micro/registry" ) -func TestLabelFilter(t *testing.T) { +func TestFilterLabel(t *testing.T) { testData := []struct { services []*registry.Service label [2]string @@ -73,7 +73,7 @@ func TestLabelFilter(t *testing.T) { } for _, data := range testData { - filter := LabelFilter(data.label[0], data.label[1]) + filter := FilterLabel(data.label[0], data.label[1]) services := filter(data.services) if len(services) != data.count { @@ -98,7 +98,7 @@ func TestLabelFilter(t *testing.T) { } } -func TestVersionFilter(t *testing.T) { +func TestFilterVersion(t *testing.T) { testData := []struct { services []*registry.Service version string @@ -135,7 +135,7 @@ func TestVersionFilter(t *testing.T) { } for _, data := range testData { - filter := VersionFilter(data.version) + filter := FilterVersion(data.version) services := filter(data.services) if len(services) != data.count { From ed764ca0b24dc503c60725593a0fb134e7e19d27 Mon Sep 17 00:00:00 2001 From: Asim Date: Sat, 23 Apr 2016 21:24:07 +0100 Subject: [PATCH 4/5] Add endpoint filter --- selector/filter.go | 19 ++++++++++ selector/filter_test.go | 81 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/selector/filter.go b/selector/filter.go index 0547b59e..53c5af39 100644 --- a/selector/filter.go +++ b/selector/filter.go @@ -4,6 +4,25 @@ import ( "github.com/micro/go-micro/registry" ) +// FilterEndpoint is an endpoint based Select Filter which will +// only return services with the endpoint specified. +func FilterEndpoint(name string) Filter { + return func(old []*registry.Service) []*registry.Service { + var services []*registry.Service + + for _, service := range old { + for _, ep := range service.Endpoints { + if ep.Name == name { + services = append(services, service) + break + } + } + } + + return services + } +} + // FilterLabel is a label based Select Filter which will // only return services with the label specified. func FilterLabel(key, val string) Filter { diff --git a/selector/filter_test.go b/selector/filter_test.go index 793c00f9..0b92aa15 100644 --- a/selector/filter_test.go +++ b/selector/filter_test.go @@ -6,6 +6,87 @@ import ( "github.com/micro/go-micro/registry" ) +func TestFilterEndpoint(t *testing.T) { + testData := []struct { + services []*registry.Service + endpoint string + count int + }{ + { + services: []*registry.Service{ + ®istry.Service{ + Name: "test", + Version: "1.0.0", + Endpoints: []*registry.Endpoint{ + ®istry.Endpoint{ + Name: "Foo.Bar", + }, + }, + }, + ®istry.Service{ + Name: "test", + Version: "1.1.0", + Endpoints: []*registry.Endpoint{ + ®istry.Endpoint{ + Name: "Baz.Bar", + }, + }, + }, + }, + endpoint: "Foo.Bar", + count: 1, + }, + { + services: []*registry.Service{ + ®istry.Service{ + Name: "test", + Version: "1.0.0", + Endpoints: []*registry.Endpoint{ + ®istry.Endpoint{ + Name: "Foo.Bar", + }, + }, + }, + ®istry.Service{ + Name: "test", + Version: "1.1.0", + Endpoints: []*registry.Endpoint{ + ®istry.Endpoint{ + Name: "Foo.Bar", + }, + }, + }, + }, + endpoint: "Bar.Baz", + count: 0, + }, + } + + for _, data := range testData { + filter := FilterEndpoint(data.endpoint) + services := filter(data.services) + + if len(services) != data.count { + t.Fatalf("Expected %d services, got %d", data.count, len(services)) + } + + for _, service := range services { + var seen bool + + for _, ep := range service.Endpoints { + if ep.Name == data.endpoint { + seen = true + break + } + } + + if seen == false && data.count > 0 { + t.Fatalf("Expected %d services but seen is %t; result %+v", data.count, seen, services) + } + } + } +} + func TestFilterLabel(t *testing.T) { testData := []struct { services []*registry.Service From d6fdfc252ee1eb3ac8c78a3125b515f7912611f0 Mon Sep 17 00:00:00 2001 From: Asim Date: Sat, 23 Apr 2016 21:37:26 +0100 Subject: [PATCH 5/5] Make it easier to add select filters --- client/options.go | 4 ++-- selector/options.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/options.go b/client/options.go index 28a4e9c4..0ab07aa5 100644 --- a/client/options.go +++ b/client/options.go @@ -187,9 +187,9 @@ func DialTimeout(d time.Duration) Option { // Call Options -func WithSelectOption(so selector.SelectOption) CallOption { +func WithSelectOption(so ...selector.SelectOption) CallOption { return func(o *CallOptions) { - o.SelectOptions = append(o.SelectOptions, so) + o.SelectOptions = append(o.SelectOptions, so...) } } diff --git a/selector/options.go b/selector/options.go index a9fe796d..47bc81c0 100644 --- a/selector/options.go +++ b/selector/options.go @@ -37,8 +37,8 @@ func Registry(r registry.Registry) Option { // WithFilter adds a filter function to the list of filters // used during the Select call. -func WithFilter(fn Filter) SelectOption { +func WithFilter(fn ...Filter) SelectOption { return func(o *SelectOptions) { - o.Filters = append(o.Filters, fn) + o.Filters = append(o.Filters, fn...) } }