package router_test import ( "bytes" "context" "fmt" "io" "io/ioutil" "log" "net/http" "testing" "time" rpc "github.com/unistack-org/micro-api-handler-rpc" rregistry "github.com/unistack-org/micro-api-router-registry" rstatic "github.com/unistack-org/micro-api-router-static" bmemory "github.com/unistack-org/micro-broker-memory" gcli "github.com/unistack-org/micro-client-grpc" jsoncodec "github.com/unistack-org/micro-codec-json" protocodec "github.com/unistack-org/micro-codec-proto" rmemory "github.com/unistack-org/micro-registry-memory" regRouter "github.com/unistack-org/micro-router-registry" gsrv "github.com/unistack-org/micro-server-grpc" pb "github.com/unistack-org/micro-tests/server/grpc/proto" "github.com/unistack-org/micro/v3/api" "github.com/unistack-org/micro/v3/api/handler" "github.com/unistack-org/micro/v3/api/router" "github.com/unistack-org/micro/v3/broker" "github.com/unistack-org/micro/v3/client" rt "github.com/unistack-org/micro/v3/router" "github.com/unistack-org/micro/v3/server" ) // server is used to implement helloworld.GreeterServer. type testServer struct { } // TestHello implements helloworld.GreeterServer func (s *testServer) Call(ctx context.Context, req *pb.Request, rsp *pb.Response) error { if req.Name == "Timeout" { time.Sleep(2 * time.Second) rsp.Msg = "Timeout" return nil } rsp.Msg = "Hello " + req.Uuid return nil } func initial(t *testing.T) (server.Server, client.Client) { //logger.DefaultLogger = logger.NewLogger(logger.WithLevel(logger.TraceLevel)) r := rmemory.NewRegistry() if err := r.Init(); err != nil { t.Fatal(err) } b := bmemory.NewBroker(broker.Registry(r)) if err := b.Init(); err != nil { t.Fatal(err) } // create a new client s := gsrv.NewServer( server.Codec("application/grpc+proto", protocodec.NewCodec()), server.Codec("application/grpc+json", protocodec.NewCodec()), server.Codec("application/json", jsoncodec.NewCodec()), server.Name("foo"), server.Broker(b), server.Registry(r), server.RegisterInterval(1*time.Second), ) rtr := regRouter.NewRouter( rt.Registry(r), ) if err := rtr.Init(); err != nil { t.Fatal(err) } // create a new server c := gcli.NewClient( client.Codec("application/grpc+proto", protocodec.NewCodec()), client.Codec("application/grpc+json", protocodec.NewCodec()), client.Codec("application/json", jsoncodec.NewCodec()), client.Registry(r), client.Router(rtr), client.Broker(b), ) h := &testServer{} pb.RegisterTestHandler(s, h) if err := s.Init(); err != nil { t.Fatalf("failed to init: %v", err) } if err := s.Start(); err != nil { t.Fatalf("failed to start: %v", err) } return s, c } func check(t *testing.T, addr string, path string, expected string, timeout bool) { var r io.Reader if timeout { r = bytes.NewBuffer([]byte(`{"name":"Timeout"}`)) } req, err := http.NewRequest("POST", fmt.Sprintf(path, addr), r) if err != nil { t.Fatalf("Failed to created http.Request: %v", err) } req.Header.Set("Content-Type", "application/json") req.Header.Set("Timeout", "1") // set timeout to 1s rsp, err := (&http.Client{}).Do(req) if err != nil { t.Fatalf("Failed to created http.Request: %v", err) } defer rsp.Body.Close() buf, err := ioutil.ReadAll(rsp.Body) if err != nil { t.Fatal(err) } jsonMsg := expected if string(buf) != jsonMsg { t.Fatalf("invalid message received, parsing error %s != %s", buf, jsonMsg) } } func TestApiTimeout(t *testing.T) { s, c := initial(t) defer s.Stop() router := rregistry.NewRouter( router.WithHandler(rpc.Handler), router.WithRegistry(s.Options().Registry), ) if err := router.Init(); err != nil { t.Fatal(err) } hrpc := rpc.NewHandler( handler.WithClient(c), handler.WithRouter(router), ) hsrv := &http.Server{ Handler: hrpc, Addr: "127.0.0.1:6543", WriteTimeout: 15 * time.Second, ReadTimeout: 15 * time.Second, IdleTimeout: 20 * time.Second, MaxHeaderBytes: 1024 * 1024 * 1, // 1Mb } go func() { log.Println(hsrv.ListenAndServe()) }() defer hsrv.Close() time.Sleep(1 * time.Second) check(t, hsrv.Addr, "http://%s/api/v0/test/call/TEST", `{"Id":"go.micro.client","Code":408,"Detail":"context deadline exceeded","Status":"Request Timeout"}`, true) } func TestRouterRegistryPcre(t *testing.T) { s, c := initial(t) defer s.Stop() router := rregistry.NewRouter( router.WithHandler(rpc.Handler), router.WithRegistry(s.Options().Registry), ) if err := router.Init(); err != nil { t.Fatal(err) } hrpc := rpc.NewHandler( handler.WithClient(c), handler.WithRouter(router), ) hsrv := &http.Server{ Handler: hrpc, Addr: "127.0.0.1:6543", WriteTimeout: 15 * time.Second, ReadTimeout: 15 * time.Second, IdleTimeout: 20 * time.Second, MaxHeaderBytes: 1024 * 1024 * 1, // 1Mb } go func() { log.Println(hsrv.ListenAndServe()) }() defer hsrv.Close() time.Sleep(1 * time.Second) check(t, hsrv.Addr, "http://%s/api/v0/test/call/TEST", `{"msg":"Hello "}`, false) } func TestRouterStaticPcre(t *testing.T) { s, c := initial(t) defer s.Stop() router := rstatic.NewRouter( router.WithHandler(rpc.Handler), router.WithRegistry(s.Options().Registry), ) if err := router.Init(); err != nil { t.Fatal(err) } err := router.Register(&api.Endpoint{ Name: "foo.Test.Call", Method: []string{"POST"}, Path: []string{"^/api/v0/test/call/?$"}, Handler: "rpc", }) if err != nil { t.Fatal(err) } hrpc := rpc.NewHandler( handler.WithClient(c), handler.WithRouter(router), ) hsrv := &http.Server{ Handler: hrpc, Addr: "127.0.0.1:6543", WriteTimeout: 15 * time.Second, ReadTimeout: 15 * time.Second, IdleTimeout: 20 * time.Second, MaxHeaderBytes: 1024 * 1024 * 1, // 1Mb } go func() { log.Println(hsrv.ListenAndServe()) }() defer hsrv.Close() time.Sleep(1 * time.Second) check(t, hsrv.Addr, "http://%s/api/v0/test/call", `{"msg":"Hello "}`, false) } func TestRouterStaticGpath(t *testing.T) { s, c := initial(t) defer s.Stop() router := rstatic.NewRouter( router.WithHandler(rpc.Handler), router.WithRegistry(s.Options().Registry), ) err := router.Register(&api.Endpoint{ Name: "foo.Test.Call", Method: []string{"POST"}, Path: []string{"/api/v0/test/call/{uuid}"}, Handler: "rpc", }) if err != nil { t.Fatal(err) } hrpc := rpc.NewHandler( handler.WithClient(c), handler.WithRouter(router), ) hsrv := &http.Server{ Handler: hrpc, Addr: "127.0.0.1:6543", WriteTimeout: 15 * time.Second, ReadTimeout: 15 * time.Second, IdleTimeout: 20 * time.Second, MaxHeaderBytes: 1024 * 1024 * 1, // 1Mb } go func() { log.Println(hsrv.ListenAndServe()) }() defer hsrv.Close() time.Sleep(1 * time.Second) check(t, hsrv.Addr, "http://%s/api/v0/test/call/TEST", `{"msg":"Hello TEST"}`, false) } func TestRouterStaticPcreInvalid(t *testing.T) { var ep *api.Endpoint var err error s, c := initial(t) defer s.Stop() router := rstatic.NewRouter( router.WithHandler(rpc.Handler), router.WithRegistry(s.Options().Registry), ) ep = &api.Endpoint{ Name: "foo.Test.Call", Method: []string{"POST"}, Path: []string{"^/api/v0/test/call/?"}, Handler: "rpc", } err = router.Register(ep) if err == nil { t.Fatalf("invalid endpoint %v", ep) } ep = &api.Endpoint{ Name: "foo.Test.Call", Method: []string{"POST"}, Path: []string{"/api/v0/test/call/?$"}, Handler: "rpc", } err = router.Register(ep) if err == nil { t.Fatalf("invalid endpoint %v", ep) } _ = c }