func TestService(t *testing.T) { str := `<html><body><h1>Hello World</h1></body></html>` fn := func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, str) } reg := mock.NewRegistry() service := NewService( Name("go.micro.web.test"), Registry(reg), ) service.HandleFunc("/", fn) go func() { if err := service.Run(); err != nil { t.Fatal(err) } }() var s []*registry.Service eventually(func() bool { var err error s, err = reg.GetService("go.micro.web.test") return err == nil }, t.Fatal) if have, want := len(s), 1; have != want { t.Fatalf("Expected %d but got %d services", want, have) } rsp, err := http.Get(fmt.Sprintf("http://%s:%d", s[0].Nodes[0].Address, s[0].Nodes[0].Port)) if err != nil { t.Fatal(err) } defer rsp.Body.Close() b, err := ioutil.ReadAll(rsp.Body) if err != nil { t.Fatal(err) } if string(b) != str { t.Errorf("Expected %s got %s", str, string(b)) } ch := make(chan os.Signal, 1) signal.Notify(ch, syscall.SIGTERM) syscall.Kill(syscall.Getpid(), syscall.SIGTERM) <-ch eventually(func() bool { _, err := reg.GetService("go.micro.web.test") return err == registry.ErrNotFound }, t.Error) }
func TestLabelSelector(t *testing.T) { counts := map[string]int{} r := mock.NewRegistry() r.Register(®istry.Service{ Name: "bar", Version: "latest", Nodes: []*registry.Node{ ®istry.Node{ Id: "1", Metadata: map[string]string{ "key1": "val1", }, }, ®istry.Node{ Id: "2", Metadata: map[string]string{ "key2": "val2", }, }, }, }) r.Register(®istry.Service{ Name: "bar", Version: "1.0.0", Nodes: []*registry.Node{ ®istry.Node{ Id: "3", Metadata: map[string]string{ "key1": "val1", }, }, ®istry.Node{ Id: "4", }, }, }) ls := NewSelector( selector.Registry(r), Label("key2", "val2"), Label("key1", "val1"), ) next, err := ls.Select("bar") if err != nil { t.Errorf("Unexpected error calling ls select: %v", err) } for i := 0; i < 100; i++ { node, err := next() if err != nil { t.Errorf("Expected node err, got err: %v", err) } counts[node.Id]++ } t.Logf("Label Select Counts %v", counts) }
func TestBreaker(t *testing.T) { // setup r := mock.NewRegistry() s := selector.NewSelector(selector.Registry(r)) c := client.NewClient( // set the selector client.Selector(s), // add the breaker wrapper client.Wrap(NewClientWrapper()), ) req := c.NewJsonRequest("test.service", "Test.Method", map[string]string{ "foo": "bar", }) var rsp map[string]interface{} // Force to point of trip for i := 0; i < (hystrix.DefaultVolumeThreshold * 2); i++ { c.Call(context.TODO(), req, rsp) } err := c.Call(context.TODO(), req, rsp) if err == nil { t.Error("Expecting tripped breaker, got nil error") } if err.Error() != "hystrix: circuit open" { t.Errorf("Expecting tripped breaker, got %v", err) } }
func sub(be *testing.B, c int) { be.StopTimer() m := mock.NewRegistry() b := NewBroker(Registry(m)) topic := uuid.NewUUID().String() if err := b.Init(); err != nil { be.Fatalf("Unexpected init error: %v", err) } if err := b.Connect(); err != nil { be.Fatalf("Unexpected connect error: %v", err) } msg := &Message{ Header: map[string]string{ "Content-Type": "application/json", }, Body: []byte(`{"message": "Hello World"}`), } var subs []Subscriber done := make(chan bool, c) for i := 0; i < c; i++ { sub, err := b.Subscribe(topic, func(p Publication) error { done <- true m := p.Message() if string(m.Body) != string(msg.Body) { be.Fatalf("Unexpected msg %s, expected %s", string(m.Body), string(msg.Body)) } return nil }, Queue("shared")) if err != nil { be.Fatalf("Unexpected subscribe error: %v", err) } subs = append(subs, sub) } for i := 0; i < be.N; i++ { be.StartTimer() if err := b.Publish(topic, msg); err != nil { be.Fatalf("Unexpected publish error: %v", err) } <-done be.StopTimer() } for _, sub := range subs { sub.Unsubscribe() } if err := b.Disconnect(); err != nil { be.Fatalf("Unexpected disconnect error: %v", err) } }
func TestConcurrentSubBroker(t *testing.T) { m := mock.NewRegistry() b := NewBroker(Registry(m)) if err := b.Init(); err != nil { t.Fatalf("Unexpected init error: %v", err) } if err := b.Connect(); err != nil { t.Fatalf("Unexpected connect error: %v", err) } msg := &Message{ Header: map[string]string{ "Content-Type": "application/json", }, Body: []byte(`{"message": "Hello World"}`), } var subs []Subscriber var wg sync.WaitGroup for i := 0; i < 10; i++ { sub, err := b.Subscribe("test", func(p Publication) error { defer wg.Done() m := p.Message() if string(m.Body) != string(msg.Body) { t.Fatalf("Unexpected msg %s, expected %s", string(m.Body), string(msg.Body)) } return nil }) if err != nil { t.Fatalf("Unexpected subscribe error: %v", err) } wg.Add(1) subs = append(subs, sub) } if err := b.Publish("test", msg); err != nil { t.Fatalf("Unexpected publish error: %v", err) } wg.Wait() for _, sub := range subs { sub.Unsubscribe() } if err := b.Disconnect(); err != nil { t.Fatalf("Unexpected disconnect error: %v", err) } }
func TestGRPCClient(t *testing.T) { l, err := net.Listen("tcp", ":0") if err != nil { t.Fatalf("failed to listen: %v", err) } defer l.Close() s := grpc.NewServer() pb.RegisterGreeterServer(s, &greeterServer{}) go s.Serve(l) defer s.Stop() parts := strings.Split(l.Addr().String(), ":") port, _ := strconv.Atoi(parts[len(parts)-1]) addr := strings.Join(parts[:len(parts)-1], ":") r := mock.NewRegistry() r.Register(®istry.Service{ Name: "test", Version: "test", Nodes: []*registry.Node{ ®istry.Node{ Id: "test-1", Address: addr, Port: port, }, }, }) se := selector.NewSelector( selector.Registry(r), ) c := NewClient( client.Registry(r), client.Selector(se), ) req := c.NewRequest("test", "/helloworld.Greeter/SayHello", &pb.HelloRequest{ Name: "John", }) rsp := pb.HelloReply{} err = c.Call(context.TODO(), req, &rsp) if err != nil { t.Fatal(err) } if rsp.Message != "Hello John" { t.Fatalf("Got unexpected response %v", rsp.Message) } }
func TestOptions(t *testing.T) { var ( name = "service-name" id = "service-id" version = "service-version" address = "service-addr" advertise = "service-adv" reg = mock.NewRegistry() registerTTL = 123 * time.Second registerInterval = 456 * time.Second handler = http.NewServeMux() metadata = map[string]string{"key": "val"} ) service := NewService( Name(name), Id(id), Version(version), Address(address), Advertise(advertise), Registry(reg), RegisterTTL(registerTTL), RegisterInterval(registerInterval), Handler(handler), Metadata(metadata), ) opts := service.Options() tests := []struct { subject string want interface{} have interface{} }{ {"name", name, opts.Name}, {"version", version, opts.Version}, {"id", id, opts.Id}, {"address", address, opts.Address}, {"advertise", advertise, opts.Advertise}, {"registry", reg, registry.DefaultRegistry}, {"registerTTL", registerTTL, opts.RegisterTTL}, {"registerInterval", registerInterval, opts.RegisterInterval}, {"handler", handler, opts.Handler}, {"metadata", metadata["key"], opts.Metadata["key"]}, } for _, tc := range tests { if tc.want != tc.have { t.Errorf("unexpected %s: want %v, have %v", tc.subject, tc.want, tc.have) } } }
func TestGRPCServer(t *testing.T) { r := mock.NewRegistry() s := NewServer( server.Name("foo"), server.Registry(r), ) pb.RegisterSayHandler(s, &sayServer{}) if err := s.Start(); err != nil { t.Fatalf("failed to start: %v", err) } if err := s.Register(); err != nil { t.Fatalf("failed to register: %v", err) } // check registration services, err := r.GetService("foo") if err != nil || len(services) == 0 { t.Fatal("failed to get service: %v # %d", err, len(services)) } defer func() { if err := s.Deregister(); err != nil { t.Fatalf("failed to deregister: %v", err) } if err := s.Stop(); err != nil { t.Fatalf("failed to stop: %v", err) } }() cc, err := grpc.Dial(s.Options().Address, grpc.WithInsecure()) if err != nil { t.Fatal("failed to dial server: %v", err) } rsp := pb.Response{} if err := grpc.Invoke(context.Background(), "Say.Hello", &pb.Request{Name: "John"}, &rsp, cc); err != nil { t.Fatal("error calling server: %v", err) } if rsp.Msg != "Hello John" { t.Fatalf("Got unexpected response %v", rsp.Msg) } }
func TestBroker(t *testing.T) { m := mock.NewRegistry() b := NewBroker(Registry(m)) if err := b.Init(); err != nil { t.Fatalf("Unexpected init error: %v", err) } if err := b.Connect(); err != nil { t.Fatalf("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() if string(m.Body) != string(msg.Body) { t.Fatalf("Unexpected msg %s, expected %s", string(m.Body), string(msg.Body)) } close(done) return nil }) if err != nil { t.Fatalf("Unexpected subscribe error: %v", err) } if err := b.Publish("test", msg); err != nil { t.Fatalf("Unexpected publish error: %v", err) } <-done sub.Unsubscribe() if err := b.Disconnect(); err != nil { t.Fatalf("Unexpected disconnect error: %v", err) } }
func TestDefaultSelector(t *testing.T) { counts := map[string]int{} rs := newDefaultSelector(Registry(mock.NewRegistry())) next, err := rs.Select("foo") if err != nil { t.Errorf("Unexpected error calling default select: %v", err) } for i := 0; i < 100; i++ { node, err := next() if err != nil { t.Errorf("Expected node err, got err: %v", err) } counts[node.Id]++ } t.Logf("Default Counts %v", counts) }
func TestCacheSelector(t *testing.T) { counts := map[string]int{} cache := NewSelector(selector.Registry(mock.NewRegistry())) next, err := cache.Select("foo") if err != nil { t.Errorf("Unexpected error calling cache select: %v", err) } for i := 0; i < 100; i++ { node, err := next() if err != nil { t.Errorf("Expected node err, got err: %v", err) } counts[node.Id]++ } t.Logf("Cache Counts %v", counts) }
func TestRoundRobinSelector(t *testing.T) { counts := map[string]int{} rr := &roundRobinSelector{ so: selector.Options{ Registry: mock.NewRegistry(), }, } next, err := rr.Select("foo") if err != nil { t.Errorf("Unexpected error calling rr select: %v", err) } for i := 0; i < 100; i++ { node, err := next() if err != nil { t.Errorf("Expected node err, got err: %v", err) } counts[node.Id]++ } t.Logf("Round Robin Counts %v", counts) }
func TestBlackListSelector(t *testing.T) { counts := map[string]int{} bl := &blackListSelector{ so: selector.Options{ Registry: mock.NewRegistry(), }, ttl: 2, bl: make(map[string]blackListNode), exit: make(chan bool), } go bl.run() defer bl.Close() next, err := bl.Select("foo") if err != nil { t.Errorf("Unexpected error calling bl select: %v", err) } for i := 0; i < 100; i++ { node, err := next() if err != nil { t.Errorf("Expected node err, got err: %v", err) } counts[node.Id]++ } t.Logf("BlackList Counts %v", counts) // test blacklisting for i := 0; i < 4; i++ { node, err := next() if err != nil { t.Errorf("Expected node err, got err: %v", err) } bl.Mark("foo", node, errors.New("blacklist")) } if node, err := next(); err != selector.ErrNoneAvailable { t.Errorf("Expected none available err, got node %v err %v", node, err) } time.Sleep(time.Second * time.Duration(bl.ttl) * 2) if _, err := next(); err != nil { t.Errorf("Unexpected err %v", err) } // test resetting for i := 0; i < 4; i++ { node, err := next() if err != nil { t.Errorf("Unexpected err: %v", err) } bl.Mark("foo", node, errors.New("blacklist")) } if node, err := next(); err != selector.ErrNoneAvailable { t.Errorf("Expected none available err, got node %v err %v", node, err) } bl.Reset("foo") if _, err := next(); err != nil { t.Errorf("Unexpected err %v", err) } }
func TestProxyHandler(t *testing.T) { r := rmock.NewRegistry() cmd.DefaultCmd = cmd.NewCmd(cmd.Registry(&r)) l, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatal(err) } defer l.Close() parts := strings.Split(l.Addr().String(), ":") var host string var port int host = parts[0] port, _ = strconv.Atoi(parts[1]) s := ®istry.Service{ Name: "go.micro.api.test", Nodes: []*registry.Node{ ®istry.Node{ Id: "1", Address: host, Port: port, }, }, } r.Register(s) defer r.Deregister(s) // setup the test handler m := http.NewServeMux() m.HandleFunc("/test/foo", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`you got served`)) }) // start http test serve go http.Serve(l, m) // create new request and writer w := httptest.NewRecorder() req, err := http.NewRequest("POST", "/test/foo", nil) if err != nil { t.Fatal(err) } // initialise the handler p := Proxy("go.micro.api", false) // execute the handler p.ServeHTTP(w, req) if w.Code != 200 { t.Fatalf("Expected 200 response got %d %s", w.Code, w.Body.String()) } if w.Body.String() != "you got served" { t.Fatal("Expected body: you got served. Got: %s", w.Body.String()) } }
func TestBlackList(t *testing.T) { return r := mock.NewRegistry() r.Register(®istry.Service{ Name: "test", Nodes: []*registry.Node{ ®istry.Node{ Id: "test-1", Address: "localhost", Port: 10001, }, ®istry.Node{ Id: "test-2", Address: "localhost", Port: 10002, }, ®istry.Node{ Id: "test-3", Address: "localhost", Port: 10002, }, }, }) rs := newSelector(selector.Registry(r)) next, err := rs.Select("test") if err != nil { t.Fatal(err) } node, err := next() if err != nil { t.Fatal(err) } for i := 0; i < 4; i++ { rs.Mark("test", node, errors.New("error")) } next, err = rs.Select("test") if err != nil { t.Fatal(err) } // still expecting 2 nodes seen := make(map[string]bool) for i := 0; i < 10; i++ { node, err = next() if err != nil { t.Fatal(err) } seen[node.Id] = true } if len(seen) != 2 { t.Fatalf("Expected seen to be 2 %+v", seen) } // blacklist all of it for i := 0; i < 20; i++ { node, err = next() if err != nil { t.Fatal(err) } rs.Mark("test", node, errors.New("error")) } next, err = rs.Select("test") if err != selector.ErrNoneAvailable { t.Fatalf("Expected %v got %v", selector.ErrNoneAvailable, err) } }
func TestHTTPServer(t *testing.T) { reg := mock.NewRegistry() // create server srv := NewServer(server.Registry(reg)) // create server mux mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`hello world`)) }) // create handler hd := srv.NewHandler(mux) // register handler if err := srv.Handle(hd); err != nil { t.Fatal(err) } // start server if err := srv.Start(); err != nil { t.Fatal(err) } // register server if err := srv.Register(); err != nil { t.Fatal(err) } // lookup server service, err := reg.GetService(server.DefaultName) if err != nil { t.Fatal(err) } if len(service) != 1 { t.Fatalf("Expected 1 service got %d: %+v", len(service), service) } if len(service[0].Nodes) != 1 { t.Fatalf("Expected 1 node got %d: %+v", len(service[0].Nodes), service[0].Nodes) } // make request rsp, err := http.Get(fmt.Sprintf("http://%s:%d", service[0].Nodes[0].Address, service[0].Nodes[0].Port)) if err != nil { t.Fatal(err) } defer rsp.Body.Close() b, err := ioutil.ReadAll(rsp.Body) if err != nil { t.Fatal(err) } if s := string(b); s != "hello world" { t.Fatalf("Expected response %s, got %s", "hello world", s) } // deregister server if err := srv.Deregister(); err != nil { t.Fatal(err) } // try get service service, err = reg.GetService(server.DefaultName) if err == nil { t.Fatal("Expected %v got %+v", registry.ErrNotFound, service) } // stop server if err := srv.Stop(); err != nil { t.Fatal(err) } }
func pub(be *testing.B, c int) { be.StopTimer() m := mock.NewRegistry() b := NewBroker(Registry(m)) topic := uuid.NewUUID().String() if err := b.Init(); err != nil { be.Fatalf("Unexpected init error: %v", err) } if err := b.Connect(); err != nil { be.Fatalf("Unexpected connect error: %v", err) } msg := &Message{ Header: map[string]string{ "Content-Type": "application/json", }, Body: []byte(`{"message": "Hello World"}`), } done := make(chan bool, c*4) sub, err := b.Subscribe(topic, func(p Publication) error { done <- true m := p.Message() if string(m.Body) != string(msg.Body) { be.Fatalf("Unexpected msg %s, expected %s", string(m.Body), string(msg.Body)) } return nil }, Queue("shared")) if err != nil { be.Fatalf("Unexpected subscribe error: %v", err) } var wg sync.WaitGroup ch := make(chan int, c*4) be.StartTimer() for i := 0; i < c; i++ { go func() { for _ = range ch { if err := b.Publish(topic, msg); err != nil { be.Fatalf("Unexpected publish error: %v", err) } select { case <-done: case <-time.After(time.Second): } wg.Done() } }() } for i := 0; i < be.N; i++ { wg.Add(1) ch <- i } wg.Wait() be.StopTimer() sub.Unsubscribe() close(ch) close(done) if err := b.Disconnect(); err != nil { be.Fatalf("Unexpected disconnect error: %v", err) } }
func TestRPCHandler(t *testing.T) { r := rmock.NewRegistry() (*cmd.DefaultOptions().Client).Init( client.Registry(r), client.Selector(selector.NewSelector(selector.Registry(r))), ) (*cmd.DefaultOptions().Server).Init( server.Name("test"), server.Registry(r), ) (*cmd.DefaultOptions().Server).Handle( (*cmd.DefaultOptions().Server).NewHandler(&TestHandler{t, metadata.Metadata{"Foo": "Bar"}}), ) if err := server.Start(); err != nil { t.Fatal(err) } if err := server.Register(); err != nil { t.Fatal(err) } w := httptest.NewRecorder() request := map[string]string{ "service": "test", "method": "TestHandler.Exec", "request": "{}", } rb, err := json.Marshal(request) if err != nil { t.Fatal(err) } b := bytes.NewBuffer(rb) req, err := http.NewRequest("POST", "/rpc", b) if err != nil { t.Fatal(err) } req.Header.Set("Content-Type", "application/json") req.Header.Set("Foo", "Bar") RPC(w, req) if err := server.Deregister(); err != nil { t.Fatal(err) } if err := server.Stop(); err != nil { t.Fatal(err) } if w.Code != 200 { t.Fatalf("Expected 200 response got %d %s", w.Code, w.Body.String()) } }