From 4da744ebdedffc9ab6d7ac4ca16918bf2e8c330a Mon Sep 17 00:00:00 2001 From: Asim Date: Mon, 14 Mar 2016 17:50:03 +0000 Subject: [PATCH 1/7] Add goreport --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 74024ab3..4679c203 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Go Micro [![GoDoc](https://godoc.org/github.com/micro/go-micro?status.svg)](https://godoc.org/github.com/micro/go-micro) [![Travis CI](https://travis-ci.org/micro/go-micro.svg?branch=master)](https://travis-ci.org/micro/go-micro) +# Go Micro [![GoDoc](https://godoc.org/github.com/micro/go-micro?status.svg)](https://godoc.org/github.com/micro/go-micro) [![Travis CI](https://travis-ci.org/micro/go-micro.svg?branch=master)](https://travis-ci.org/micro/go-micro) [![Go Report Card](https://goreportcard.com/badge/micro/go-micro)](https://goreportcard.com/report/github.com/micro/go-micro) Go Micro is a pluggable RPC based microservice library which provides the fundamental building blocks for writing distributed applications. It is part of the [Micro](https://github.com/micro/micro) toolkit. It supports Proto-RPC and JSON-RPC as the request/response protocol out of the box and defaults to Consul for discovery. From 6028c2f9e88ed724556d71c7f2af015d6b0c628d Mon Sep 17 00:00:00 2001 From: Asim Date: Mon, 14 Mar 2016 17:50:18 +0000 Subject: [PATCH 2/7] Add transport comms tests --- transport/http_transport_test.go | 74 +++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 7 deletions(-) diff --git a/transport/http_transport_test.go b/transport/http_transport_test.go index 72feddd6..0afde154 100644 --- a/transport/http_transport_test.go +++ b/transport/http_transport_test.go @@ -7,7 +7,17 @@ import ( "github.com/micro/go-micro/transport" ) -func TestHTTPTransport_PortRange(t *testing.T) { +func expectedPort(t *testing.T, expected string, lsn transport.Listener) { + parts := strings.Split(lsn.Addr(), ":") + port := parts[len(parts)-1] + + if port != expected { + lsn.Close() + t.Errorf("Expected address to be `%s`, got `%s`", expected, port) + } +} + +func TestHTTPTransportPortRange(t *testing.T) { tp := transport.NewTransport([]string{}) lsn1, err := tp.Listen(":44444-44448") @@ -32,12 +42,62 @@ func TestHTTPTransport_PortRange(t *testing.T) { lsn2.Close() } -func expectedPort(t *testing.T, expected string, lsn transport.Listener) { - parts := strings.Split(lsn.Addr(), ":") - port := parts[len(parts)-1] +func TestHTTPTransportCommunication(t *testing.T) { + tr := transport.NewTransport([]string{}) - if port != expected { - lsn.Close() - t.Errorf("Expected address to be `%s`, got `%s`", expected, port) + l, err := tr.Listen(":0") + if err != nil { + t.Errorf("Unexpected listen err: %v", err) + } + defer l.Close() + + fn := func(sock transport.Socket) { + defer sock.Close() + + for { + var m transport.Message + if err := sock.Recv(&m); err != nil { + return + } + + t.Logf("Successfully received %+v", m) + + if err := sock.Send(&m); err != nil { + return + } + } + } + + go func() { + if err := l.Accept(fn); err != nil { + t.Errorf("Unexpected accept err: %v", err) + } + }() + + c, err := tr.Dial(l.Addr()) + if err != nil { + t.Errorf("Unexpected dial err: %v", err) + } + defer c.Close() + + m := transport.Message{ + Header: map[string]string{ + "Content-Type": "application/json", + }, + Body: []byte(`{"message": "Hello World"}`), + } + + if err := c.Send(&m); err != nil { + t.Errorf("Unexpected send err: %v", err) + } + + var rm transport.Message + + if err := c.Recv(&rm); err != nil { + t.Errorf("Unexpected recv err: %v", err) + } + + if string(rm.Body) != string(m.Body) { + t.Errorf("Expected %v, got %v", m.Body, rm.Body) } } From 77177508ce5cd7d9f76a820cf268557719515c4c Mon Sep 17 00:00:00 2001 From: Asim Date: Mon, 14 Mar 2016 17:57:49 +0000 Subject: [PATCH 3/7] Don't bother closing the socket --- transport/http_transport_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/transport/http_transport_test.go b/transport/http_transport_test.go index 0afde154..69bdc374 100644 --- a/transport/http_transport_test.go +++ b/transport/http_transport_test.go @@ -52,8 +52,6 @@ func TestHTTPTransportCommunication(t *testing.T) { defer l.Close() fn := func(sock transport.Socket) { - defer sock.Close() - for { var m transport.Message if err := sock.Recv(&m); err != nil { From fe1fde8c59d995b4fb16b07e4754693149c3e787 Mon Sep 17 00:00:00 2001 From: Asim Date: Mon, 14 Mar 2016 18:20:38 +0000 Subject: [PATCH 4/7] go 1.4 doesn't like closed connection, check we closed the listener --- transport/http_transport_test.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/transport/http_transport_test.go b/transport/http_transport_test.go index 69bdc374..596b3bbb 100644 --- a/transport/http_transport_test.go +++ b/transport/http_transport_test.go @@ -52,6 +52,8 @@ func TestHTTPTransportCommunication(t *testing.T) { defer l.Close() fn := func(sock transport.Socket) { + defer sock.Close() + for { var m transport.Message if err := sock.Recv(&m); err != nil { @@ -66,9 +68,15 @@ func TestHTTPTransportCommunication(t *testing.T) { } } + done := make(chan bool) + go func() { if err := l.Accept(fn); err != nil { - t.Errorf("Unexpected accept err: %v", err) + select { + case <-done: + default: + t.Errorf("Unexpected accept err: %v", err) + } } }() @@ -98,4 +106,6 @@ func TestHTTPTransportCommunication(t *testing.T) { if string(rm.Body) != string(m.Body) { t.Errorf("Expected %v, got %v", m.Body, rm.Body) } + + close(done) } From bbcbd2a44615f4cee30c56ca5ca0b2653f2890e1 Mon Sep 17 00:00:00 2001 From: Asim Date: Mon, 14 Mar 2016 18:32:08 +0000 Subject: [PATCH 5/7] Basic metadata retrieval test --- metadata/metadata_test.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 metadata/metadata_test.go diff --git a/metadata/metadata_test.go b/metadata/metadata_test.go new file mode 100644 index 00000000..845789da --- /dev/null +++ b/metadata/metadata_test.go @@ -0,0 +1,28 @@ +package metadata + +import ( + "testing" + + "golang.org/x/net/context" +) + +func TestMetadataContext(t *testing.T) { + md := Metadata{ + "foo": "bar", + } + + ctx := NewContext(context.TODO(), md) + + emd, ok := FromContext(ctx) + if !ok { + t.Errorf("Unexpected error retrieving metadata, got %t", ok) + } + + if emd["foo"] != md["foo"] { + t.Errorf("Expected key: %s val: %s, got key: %s val: %s", "foo", md["foo"], "foo", emd["foo"]) + } + + if i := len(emd); i != 1 { + t.Errorf("Expected metadata length 1 got %d", i) + } +} From 15db053bc6e7c8ba13b3083dfe4d1b42dff3c378 Mon Sep 17 00:00:00 2001 From: Asim Date: Mon, 14 Mar 2016 19:15:42 +0000 Subject: [PATCH 6/7] update mock tests --- registry/mock/helper.go | 76 +++++++++++++++++++ registry/mock/helper_test.go | 78 ++++++++++++++++++++ registry/mock/mock.go | 78 +++++++++++--------- registry/mock/mock_test.go | 138 +++++++++++++++++++++++++++++++++++ 4 files changed, 336 insertions(+), 34 deletions(-) create mode 100644 registry/mock/helper.go create mode 100644 registry/mock/helper_test.go create mode 100644 registry/mock/mock_test.go diff --git a/registry/mock/helper.go b/registry/mock/helper.go new file mode 100644 index 00000000..aadb3839 --- /dev/null +++ b/registry/mock/helper.go @@ -0,0 +1,76 @@ +package mock + +import ( + "github.com/micro/go-micro/registry" +) + +func addNodes(old, neu []*registry.Node) []*registry.Node { + for _, n := range neu { + var seen bool + for i, o := range old { + if o.Id == n.Id { + seen = true + old[i] = n + break + } + } + if !seen { + old = append(old, n) + } + } + return old +} + +func addServices(old, neu []*registry.Service) []*registry.Service { + for _, s := range neu { + var seen bool + for i, o := range old { + if o.Version == s.Version { + s.Nodes = addNodes(o.Nodes, s.Nodes) + seen = true + old[i] = s + break + } + } + if !seen { + old = append(old, s) + } + } + return old +} + +func delNodes(old, del []*registry.Node) []*registry.Node { + var nodes []*registry.Node + for _, o := range old { + var rem bool + for _, n := range del { + if o.Id == n.Id { + rem = true + break + } + } + if !rem { + nodes = append(nodes, o) + } + } + return nodes +} + +func delServices(old, del []*registry.Service) []*registry.Service { + var services []*registry.Service + for i, o := range old { + var rem bool + for _, s := range del { + if o.Version == s.Version { + old[i].Nodes = delNodes(o.Nodes, s.Nodes) + if len(old[i].Nodes) == 0 { + rem = true + } + } + } + if !rem { + services = append(services, o) + } + } + return services +} diff --git a/registry/mock/helper_test.go b/registry/mock/helper_test.go new file mode 100644 index 00000000..a9571d1a --- /dev/null +++ b/registry/mock/helper_test.go @@ -0,0 +1,78 @@ +package mock + +import ( + "testing" + + "github.com/micro/go-micro/registry" +) + +func TestDelServices(t *testing.T) { + services := []*registry.Service{ + { + Name: "foo", + Version: "1.0.0", + Nodes: []*registry.Node{ + { + Id: "foo-123", + Address: "localhost", + Port: 9999, + }, + }, + }, + { + Name: "foo", + Version: "1.0.0", + Nodes: []*registry.Node{ + { + Id: "foo-123", + Address: "localhost", + Port: 6666, + }, + }, + }, + } + + servs := delServices([]*registry.Service{services[0]}, []*registry.Service{services[1]}) + if i := len(servs); i > 0 { + t.Errorf("Expected 0 nodes, got %d: %+v", i, servs) + } + t.Logf("Services %+v", servs) +} + +func TestDelNodes(t *testing.T) { + services := []*registry.Service{ + { + Name: "foo", + Version: "1.0.0", + Nodes: []*registry.Node{ + { + Id: "foo-123", + Address: "localhost", + Port: 9999, + }, + { + Id: "foo-321", + Address: "localhost", + Port: 6666, + }, + }, + }, + { + Name: "foo", + Version: "1.0.0", + Nodes: []*registry.Node{ + { + Id: "foo-123", + Address: "localhost", + Port: 6666, + }, + }, + }, + } + + nodes := delNodes(services[0].Nodes, services[1].Nodes) + if i := len(nodes); i != 1 { + t.Errorf("Expected only 1 node, got %d: %+v", i, nodes) + } + t.Logf("Nodes %+v", nodes) +} diff --git a/registry/mock/mock.go b/registry/mock/mock.go index ced5f308..2478bf3f 100644 --- a/registry/mock/mock.go +++ b/registry/mock/mock.go @@ -8,48 +8,54 @@ type MockRegistry struct { Services map[string][]*registry.Service } -func (m *MockRegistry) init() { - // add some mock data - m.Services["foo"] = []*registry.Service{ - { - Name: "foo", - Version: "1.0.0", - Nodes: []*registry.Node{ - { - Id: "foo-1.0.0-123", - Address: "localhost", - Port: 9999, - }, - { - Id: "foo-1.0.0-321", - Address: "localhost", - Port: 9999, +var ( + mockData = map[string][]*registry.Service{ + "foo": []*registry.Service{ + { + Name: "foo", + Version: "1.0.0", + Nodes: []*registry.Node{ + { + Id: "foo-1.0.0-123", + Address: "localhost", + Port: 9999, + }, + { + Id: "foo-1.0.0-321", + Address: "localhost", + Port: 9999, + }, }, }, - }, - { - Name: "foo", - Version: "1.0.1", - Nodes: []*registry.Node{ - { - Id: "foo-1.0.1-321", - Address: "localhost", - Port: 6666, + { + Name: "foo", + Version: "1.0.1", + Nodes: []*registry.Node{ + { + Id: "foo-1.0.1-321", + Address: "localhost", + Port: 6666, + }, }, }, - }, - { - Name: "foo", - Version: "1.0.3", - Nodes: []*registry.Node{ - { - Id: "foo-1.0.3-345", - Address: "localhost", - Port: 8888, + { + Name: "foo", + Version: "1.0.3", + Nodes: []*registry.Node{ + { + Id: "foo-1.0.3-345", + Address: "localhost", + Port: 8888, + }, }, }, }, } +) + +func (m *MockRegistry) init() { + // add some mock data + m.Services = mockData } func (m *MockRegistry) GetService(service string) ([]*registry.Service, error) { @@ -70,10 +76,14 @@ func (m *MockRegistry) ListServices() ([]*registry.Service, error) { } func (m *MockRegistry) Register(s *registry.Service, opts ...registry.RegisterOption) error { + services := addServices(m.Services[s.Name], []*registry.Service{s}) + m.Services[s.Name] = services return nil } func (m *MockRegistry) Deregister(s *registry.Service) error { + services := delServices(m.Services[s.Name], []*registry.Service{s}) + m.Services[s.Name] = services return nil } diff --git a/registry/mock/mock_test.go b/registry/mock/mock_test.go new file mode 100644 index 00000000..212599d7 --- /dev/null +++ b/registry/mock/mock_test.go @@ -0,0 +1,138 @@ +package mock + +import ( + "testing" + + "github.com/micro/go-micro/registry" +) + +var ( + testData = map[string][]*registry.Service{ + "foo": []*registry.Service{ + { + Name: "foo", + Version: "1.0.0", + Nodes: []*registry.Node{ + { + Id: "foo-1.0.0-123", + Address: "localhost", + Port: 9999, + }, + { + Id: "foo-1.0.0-321", + Address: "localhost", + Port: 9999, + }, + }, + }, + { + Name: "foo", + Version: "1.0.1", + Nodes: []*registry.Node{ + { + Id: "foo-1.0.1-321", + Address: "localhost", + Port: 6666, + }, + }, + }, + { + Name: "foo", + Version: "1.0.3", + Nodes: []*registry.Node{ + { + Id: "foo-1.0.3-345", + Address: "localhost", + Port: 8888, + }, + }, + }, + }, + "bar": []*registry.Service{ + { + Name: "bar", + Version: "default", + Nodes: []*registry.Node{ + { + Id: "bar-1.0.0-123", + Address: "localhost", + Port: 9999, + }, + { + Id: "bar-1.0.0-321", + Address: "localhost", + Port: 9999, + }, + }, + }, + { + Name: "bar", + Version: "latest", + Nodes: []*registry.Node{ + { + Id: "bar-1.0.1-321", + Address: "localhost", + Port: 6666, + }, + }, + }, + }, + } +) + +func TestMockRegistry(t *testing.T) { + m := NewRegistry() + + fn := func(k string, v []*registry.Service) { + services, err := m.GetService(k) + if err != nil { + t.Errorf("Unexpected error getting service %s: %v", k, err) + } + + if len(services) != len(v) { + t.Errorf("Expected %d services for %s, got %d", len(v), k, len(services)) + } + + for _, service := range v { + var seen bool + for _, s := range services { + if s.Version == service.Version { + seen = true + break + } + } + if !seen { + t.Errorf("expected to find version %s", service.Version) + } + } + } + + // test existing mock data + for k, v := range mockData { + fn(k, v) + } + + // register data + for _, v := range testData { + for _, service := range v { + if err := m.Register(service); err != nil { + t.Errorf("Unexpected register error: %v", err) + } + } + } + + // using test data + for k, v := range testData { + + fn(k, v) + } + + // deregister + for _, v := range testData { + for _, service := range v { + if err := m.Deregister(service); err != nil { + t.Errorf("Unexpected deregister error: %v", err) + } + } + } +} From f8fcb74f797ecfa3bbb80409e61a30bc08edc7d0 Mon Sep 17 00:00:00 2001 From: Asim Date: Mon, 14 Mar 2016 19:37:51 +0000 Subject: [PATCH 7/7] broker test --- broker/http_broker_test.go | 55 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 broker/http_broker_test.go diff --git a/broker/http_broker_test.go b/broker/http_broker_test.go new file mode 100644 index 00000000..cdccfaf2 --- /dev/null +++ b/broker/http_broker_test.go @@ -0,0 +1,55 @@ +package broker + +import ( + "testing" + + "github.com/micro/go-micro/registry/mock" +) + +func TestBroker(t *testing.T) { + m := mock.NewRegistry() + b := NewBroker([]string{}, Registry(m)) + + if err := b.Init(); err != nil { + t.Errorf("Unexpected init error: %v", err) + } + + if err := b.Connect(); err != nil { + t.Errorf("Unexpected connect error: %v", err) + } + + msg := &Message{ + Header: map[string]string{ + "Content-Type": "application/json", + }, + Body: []byte(`{"message": "Hello World"}`), + } + + done := make(chan bool) + + sub, err := b.Subscribe("test", func(p Publication) error { + m := p.Message() + t.Logf("Received message %+v", m) + + if string(m.Body) != string(msg.Body) { + t.Errorf("Unexpected msg %s, expected %s", string(m.Body), string(msg.Body)) + } + + close(done) + return nil + }) + if err != nil { + t.Errorf("Unexpected subscribe error: %v", err) + } + + if err := b.Publish("test", msg); err != nil { + t.Errorf("Unexpected publish error: %v", err) + } + + <-done + sub.Unsubscribe() + + if err := b.Disconnect(); err != nil { + t.Errorf("Unexpected disconnect error: %v", err) + } +}