| @@ -1,4 +1,4 @@ | ||||
| # Go Micro [](https://godoc.org/github.com/micro/go-micro) [](https://travis-ci.org/micro/go-micro) | ||||
| # Go Micro [](https://godoc.org/github.com/micro/go-micro) [](https://travis-ci.org/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. | ||||
|  | ||||
|   | ||||
							
								
								
									
										55
									
								
								broker/http_broker_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								broker/http_broker_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										28
									
								
								metadata/metadata_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								metadata/metadata_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										76
									
								
								registry/mock/helper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								registry/mock/helper.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										78
									
								
								registry/mock/helper_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								registry/mock/helper_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||
| } | ||||
| @@ -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 | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										138
									
								
								registry/mock/mock_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								registry/mock/mock_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -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,70 @@ 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 | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	done := make(chan bool) | ||||
|  | ||||
| 	go func() { | ||||
| 		if err := l.Accept(fn); err != nil { | ||||
| 			select { | ||||
| 			case <-done: | ||||
| 			default: | ||||
| 				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) | ||||
| 	} | ||||
|  | ||||
| 	close(done) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user