package web import ( "crypto/tls" "fmt" "io" "net/http" "os" "os/signal" "syscall" "testing" "time" "go-micro.dev/v5/registry" ) func TestService(t *testing.T) { var ( beforeStartCalled bool afterStartCalled bool beforeStopCalled bool afterStopCalled bool str = `

Hello World

` fn = func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, str) } reg = registry.NewMemoryRegistry() ) beforeStart := func() error { beforeStartCalled = true return nil } afterStart := func() error { afterStartCalled = true return nil } beforeStop := func() error { beforeStopCalled = true return nil } afterStop := func() error { afterStopCalled = true return nil } service := NewService( Name("go.micro.web.test"), Registry(reg), BeforeStart(beforeStart), AfterStart(afterStart), BeforeStop(beforeStop), AfterStop(afterStop), ) service.HandleFunc("/", fn) errCh := make(chan error, 1) go func() { errCh <- service.Run() close(errCh) }() 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", s[0].Nodes[0].Address)) if err != nil { t.Fatal(err) } defer rsp.Body.Close() b, err := io.ReadAll(rsp.Body) if err != nil { t.Fatal(err) } if string(b) != str { t.Errorf("Expected %s got %s", str, string(b)) } callbackTests := []struct { subject string have interface{} }{ {"beforeStartCalled", beforeStartCalled}, {"afterStartCalled", afterStartCalled}, } for _, tt := range callbackTests { if tt.have != true { t.Errorf("unexpected %s: want true, have false", tt.subject) } } select { case err := <-errCh: if err != nil { t.Fatalf("service.Run():%v", err) } case <-time.After(time.Duration(time.Second)): if len(os.Getenv("IN_TRAVIS_CI")) == 0 { t.Logf("service.Run() survived a client request without an error") } } ch := make(chan os.Signal, 1) signal.Notify(ch, syscall.SIGTERM) p, _ := os.FindProcess(os.Getpid()) p.Signal(syscall.SIGTERM) <-ch select { case err := <-errCh: if err != nil { t.Fatalf("service.Run():%v", err) } else { if len(os.Getenv("IN_TRAVIS_CI")) == 0 { t.Log("service.Run() nil return on syscall.SIGTERM") } } case <-time.After(time.Duration(time.Second)): if len(os.Getenv("IN_TRAVIS_CI")) == 0 { t.Logf("service.Run() survived a client request without an error") } } eventually(func() bool { _, err := reg.GetService("go.micro.web.test") return err == registry.ErrNotFound }, t.Error) callbackTests = []struct { subject string have interface{} }{ {"beforeStopCalled", beforeStopCalled}, {"afterStopCalled", afterStopCalled}, } for _, tt := range callbackTests { if tt.have != true { t.Errorf("unexpected %s: want true, have false", tt.subject) } } } func TestOptions(t *testing.T) { var ( name = "service-name" id = "service-id" version = "service-version" address = "service-addr:8080" advertise = "service-adv:8080" reg = registry.NewMemoryRegistry() registerTTL = 123 * time.Second registerInterval = 456 * time.Second handler = http.NewServeMux() metadata = map[string]string{"key": "val"} secure = true ) service := NewService( Name(name), Id(id), Version(version), Address(address), Advertise(advertise), Registry(reg), RegisterTTL(registerTTL), RegisterInterval(registerInterval), Handler(handler), Metadata(metadata), Secure(secure), ) 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, opts.Registry}, {"registerTTL", registerTTL, opts.RegisterTTL}, {"registerInterval", registerInterval, opts.RegisterInterval}, {"handler", handler, opts.Handler}, {"metadata", metadata["key"], opts.Metadata["key"]}, {"secure", secure, opts.Secure}, } for _, tc := range tests { if tc.want != tc.have { t.Errorf("unexpected %s: want %v, have %v", tc.subject, tc.want, tc.have) } } } func eventually(pass func() bool, fail func(...interface{})) { tick := time.NewTicker(10 * time.Millisecond) defer tick.Stop() timeout := time.After(time.Second) for { select { case <-timeout: fail("timed out") return case <-tick.C: if pass() { return } } } } func TestTLS(t *testing.T) { var ( str = `

Hello World

` fn = func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, str) } secure = true reg = registry.NewMemoryRegistry() ) service := NewService( Name("go.micro.web.test"), Secure(secure), Registry(reg), ) service.HandleFunc("/", fn) errCh := make(chan error, 1) go func() { errCh <- service.Run() close(errCh) }() 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) } tr := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, } client := &http.Client{Transport: tr} rsp, err := client.Get(fmt.Sprintf("https://%s", s[0].Nodes[0].Address)) if err != nil { t.Fatal(err) } defer rsp.Body.Close() b, err := io.ReadAll(rsp.Body) if err != nil { t.Fatal(err) } if string(b) != str { t.Errorf("Expected %s got %s", str, string(b)) } select { case err := <-errCh: if err != nil { t.Fatalf("service.Run():%v", err) } case <-time.After(time.Duration(time.Second)): if len(os.Getenv("IN_TRAVIS_CI")) == 0 { t.Logf("service.Run() survived a client request without an error") } } }