go-micro.dev/v5@v5.12.0/web/service_test.go (about)

     1  package web
     2  
     3  import (
     4  	"crypto/tls"
     5  	"fmt"
     6  	"io"
     7  	"net/http"
     8  	"os"
     9  	"os/signal"
    10  	"syscall"
    11  	"testing"
    12  	"time"
    13  
    14  	"go-micro.dev/v5/registry"
    15  )
    16  
    17  func TestService(t *testing.T) {
    18  	var (
    19  		beforeStartCalled bool
    20  		afterStartCalled  bool
    21  		beforeStopCalled  bool
    22  		afterStopCalled   bool
    23  		str               = `<html><body><h1>Hello World</h1></body></html>`
    24  		fn                = func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, str) }
    25  		reg               = registry.NewMemoryRegistry()
    26  	)
    27  
    28  	beforeStart := func() error {
    29  		beforeStartCalled = true
    30  		return nil
    31  	}
    32  
    33  	afterStart := func() error {
    34  		afterStartCalled = true
    35  		return nil
    36  	}
    37  
    38  	beforeStop := func() error {
    39  		beforeStopCalled = true
    40  		return nil
    41  	}
    42  
    43  	afterStop := func() error {
    44  		afterStopCalled = true
    45  		return nil
    46  	}
    47  
    48  	service := NewService(
    49  		Name("go.micro.web.test"),
    50  		Registry(reg),
    51  		BeforeStart(beforeStart),
    52  		AfterStart(afterStart),
    53  		BeforeStop(beforeStop),
    54  		AfterStop(afterStop),
    55  	)
    56  
    57  	service.HandleFunc("/", fn)
    58  
    59  	errCh := make(chan error, 1)
    60  	go func() {
    61  		errCh <- service.Run()
    62  		close(errCh)
    63  	}()
    64  
    65  	var s []*registry.Service
    66  
    67  	eventually(func() bool {
    68  		var err error
    69  		s, err = reg.GetService("go.micro.web.test")
    70  		return err == nil
    71  	}, t.Fatal)
    72  
    73  	if have, want := len(s), 1; have != want {
    74  		t.Fatalf("Expected %d but got %d services", want, have)
    75  	}
    76  
    77  	rsp, err := http.Get(fmt.Sprintf("http://%s", s[0].Nodes[0].Address))
    78  	if err != nil {
    79  		t.Fatal(err)
    80  	}
    81  	defer rsp.Body.Close()
    82  
    83  	b, err := io.ReadAll(rsp.Body)
    84  	if err != nil {
    85  		t.Fatal(err)
    86  	}
    87  
    88  	if string(b) != str {
    89  		t.Errorf("Expected %s got %s", str, string(b))
    90  	}
    91  
    92  	callbackTests := []struct {
    93  		subject string
    94  		have    interface{}
    95  	}{
    96  		{"beforeStartCalled", beforeStartCalled},
    97  		{"afterStartCalled", afterStartCalled},
    98  	}
    99  
   100  	for _, tt := range callbackTests {
   101  		if tt.have != true {
   102  			t.Errorf("unexpected %s: want true, have false", tt.subject)
   103  		}
   104  	}
   105  
   106  	select {
   107  	case err := <-errCh:
   108  		if err != nil {
   109  			t.Fatalf("service.Run():%v", err)
   110  		}
   111  	case <-time.After(time.Duration(time.Second)):
   112  		if len(os.Getenv("IN_TRAVIS_CI")) == 0 {
   113  			t.Logf("service.Run() survived a client request without an error")
   114  		}
   115  	}
   116  
   117  	ch := make(chan os.Signal, 1)
   118  	signal.Notify(ch, syscall.SIGTERM)
   119  	p, _ := os.FindProcess(os.Getpid())
   120  	p.Signal(syscall.SIGTERM)
   121  
   122  	<-ch
   123  
   124  	select {
   125  	case err := <-errCh:
   126  		if err != nil {
   127  			t.Fatalf("service.Run():%v", err)
   128  		} else {
   129  			if len(os.Getenv("IN_TRAVIS_CI")) == 0 {
   130  				t.Log("service.Run() nil return on syscall.SIGTERM")
   131  			}
   132  		}
   133  	case <-time.After(time.Duration(time.Second)):
   134  		if len(os.Getenv("IN_TRAVIS_CI")) == 0 {
   135  			t.Logf("service.Run() survived a client request without an error")
   136  		}
   137  	}
   138  
   139  	eventually(func() bool {
   140  		_, err := reg.GetService("go.micro.web.test")
   141  		return err == registry.ErrNotFound
   142  	}, t.Error)
   143  
   144  	callbackTests = []struct {
   145  		subject string
   146  		have    interface{}
   147  	}{
   148  		{"beforeStopCalled", beforeStopCalled},
   149  		{"afterStopCalled", afterStopCalled},
   150  	}
   151  
   152  	for _, tt := range callbackTests {
   153  		if tt.have != true {
   154  			t.Errorf("unexpected %s: want true, have false", tt.subject)
   155  		}
   156  	}
   157  }
   158  
   159  func TestOptions(t *testing.T) {
   160  	var (
   161  		name             = "service-name"
   162  		id               = "service-id"
   163  		version          = "service-version"
   164  		address          = "service-addr:8080"
   165  		advertise        = "service-adv:8080"
   166  		reg              = registry.NewMemoryRegistry()
   167  		registerTTL      = 123 * time.Second
   168  		registerInterval = 456 * time.Second
   169  		handler          = http.NewServeMux()
   170  		metadata         = map[string]string{"key": "val"}
   171  		secure           = true
   172  	)
   173  
   174  	service := NewService(
   175  		Name(name),
   176  		Id(id),
   177  		Version(version),
   178  		Address(address),
   179  		Advertise(advertise),
   180  		Registry(reg),
   181  		RegisterTTL(registerTTL),
   182  		RegisterInterval(registerInterval),
   183  		Handler(handler),
   184  		Metadata(metadata),
   185  		Secure(secure),
   186  	)
   187  
   188  	opts := service.Options()
   189  
   190  	tests := []struct {
   191  		subject string
   192  		want    interface{}
   193  		have    interface{}
   194  	}{
   195  		{"name", name, opts.Name},
   196  		{"version", version, opts.Version},
   197  		{"id", id, opts.Id},
   198  		{"address", address, opts.Address},
   199  		{"advertise", advertise, opts.Advertise},
   200  		{"registry", reg, opts.Registry},
   201  		{"registerTTL", registerTTL, opts.RegisterTTL},
   202  		{"registerInterval", registerInterval, opts.RegisterInterval},
   203  		{"handler", handler, opts.Handler},
   204  		{"metadata", metadata["key"], opts.Metadata["key"]},
   205  		{"secure", secure, opts.Secure},
   206  	}
   207  
   208  	for _, tc := range tests {
   209  		if tc.want != tc.have {
   210  			t.Errorf("unexpected %s: want %v, have %v", tc.subject, tc.want, tc.have)
   211  		}
   212  	}
   213  }
   214  
   215  func eventually(pass func() bool, fail func(...interface{})) {
   216  	tick := time.NewTicker(10 * time.Millisecond)
   217  	defer tick.Stop()
   218  
   219  	timeout := time.After(time.Second)
   220  
   221  	for {
   222  		select {
   223  		case <-timeout:
   224  			fail("timed out")
   225  			return
   226  		case <-tick.C:
   227  			if pass() {
   228  				return
   229  			}
   230  		}
   231  	}
   232  }
   233  
   234  func TestTLS(t *testing.T) {
   235  	var (
   236  		str    = `<html><body><h1>Hello World</h1></body></html>`
   237  		fn     = func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, str) }
   238  		secure = true
   239  		reg    = registry.NewMemoryRegistry()
   240  	)
   241  
   242  	service := NewService(
   243  		Name("go.micro.web.test"),
   244  		Secure(secure),
   245  		Registry(reg),
   246  	)
   247  
   248  	service.HandleFunc("/", fn)
   249  
   250  	errCh := make(chan error, 1)
   251  	go func() {
   252  		errCh <- service.Run()
   253  		close(errCh)
   254  	}()
   255  
   256  	var s []*registry.Service
   257  
   258  	eventually(func() bool {
   259  		var err error
   260  		s, err = reg.GetService("go.micro.web.test")
   261  		return err == nil
   262  	}, t.Fatal)
   263  
   264  	if have, want := len(s), 1; have != want {
   265  		t.Fatalf("Expected %d but got %d services", want, have)
   266  	}
   267  
   268  	tr := &http.Transport{
   269  		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
   270  	}
   271  	client := &http.Client{Transport: tr}
   272  	rsp, err := client.Get(fmt.Sprintf("https://%s", s[0].Nodes[0].Address))
   273  	if err != nil {
   274  		t.Fatal(err)
   275  	}
   276  	defer rsp.Body.Close()
   277  
   278  	b, err := io.ReadAll(rsp.Body)
   279  	if err != nil {
   280  		t.Fatal(err)
   281  	}
   282  
   283  	if string(b) != str {
   284  		t.Errorf("Expected %s got %s", str, string(b))
   285  	}
   286  
   287  	select {
   288  	case err := <-errCh:
   289  		if err != nil {
   290  			t.Fatalf("service.Run():%v", err)
   291  		}
   292  	case <-time.After(time.Duration(time.Second)):
   293  		if len(os.Getenv("IN_TRAVIS_CI")) == 0 {
   294  			t.Logf("service.Run() survived a client request without an error")
   295  		}
   296  	}
   297  }