github.com/bufbuild/connect-grpchealth-go@v1.1.1/grpchealth_test.go (about)

     1  // Copyright 2022-2023 Buf Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package grpchealth
    16  
    17  import (
    18  	"context"
    19  	"errors"
    20  	"net/http"
    21  	"net/http/httptest"
    22  	"testing"
    23  
    24  	"github.com/bufbuild/connect-go"
    25  	healthv1 "github.com/bufbuild/connect-grpchealth-go/internal/gen/go/connectext/grpc/health/v1"
    26  )
    27  
    28  func TestHealth(t *testing.T) {
    29  	const (
    30  		userFQN = "acme.user.v1.UserService"
    31  		unknown = "foobar"
    32  	)
    33  	t.Parallel()
    34  	mux := http.NewServeMux()
    35  	checker := NewStaticChecker(userFQN)
    36  	mux.Handle(NewHandler(checker))
    37  	server := httptest.NewUnstartedServer(mux)
    38  	server.EnableHTTP2 = true
    39  	server.StartTLS()
    40  	t.Cleanup(server.Close)
    41  
    42  	client := connect.NewClient[healthv1.HealthCheckRequest, healthv1.HealthCheckResponse](
    43  		server.Client(),
    44  		server.URL+"/grpc.health.v1.Health/Check",
    45  		connect.WithGRPC(),
    46  	)
    47  
    48  	assertStatus := func(
    49  		t *testing.T,
    50  		service string,
    51  		expect Status,
    52  	) {
    53  		t.Helper()
    54  		res, err := client.CallUnary(
    55  			context.Background(),
    56  			connect.NewRequest(&healthv1.HealthCheckRequest{Service: service}),
    57  		)
    58  		if err != nil {
    59  			t.Fatalf(err.Error())
    60  		}
    61  		if Status(res.Msg.Status) != expect {
    62  			t.Fatalf("got status %v, expected %v", res.Msg.Status, expect)
    63  		}
    64  	}
    65  	assertUnknown := func(
    66  		t *testing.T,
    67  		service string,
    68  	) {
    69  		t.Helper()
    70  		_, err := client.CallUnary(
    71  			context.Background(),
    72  			connect.NewRequest(&healthv1.HealthCheckRequest{Service: service}),
    73  		)
    74  		if err == nil {
    75  			t.Fatalf("expected error checking unknown service %q", service)
    76  		}
    77  		var connectErr *connect.Error
    78  		if ok := errors.As(err, &connectErr); !ok {
    79  			t.Fatalf("got %v (%T), expected a *connect.Error", err, err)
    80  		}
    81  		if code := connectErr.Code(); code != connect.CodeNotFound {
    82  			t.Fatalf("check %q: got code %v, expected CodeNotFound", service, code)
    83  		}
    84  	}
    85  
    86  	assertStatus(t, "" /* process */, StatusServing)
    87  
    88  	assertStatus(t, userFQN, StatusServing)
    89  	checker.SetStatus(userFQN, StatusNotServing)
    90  	assertStatus(t, userFQN, StatusNotServing)
    91  
    92  	assertUnknown(t, unknown)
    93  	checker.SetStatus(unknown, StatusServing)
    94  	assertStatus(t, unknown, StatusServing)
    95  
    96  	watcher := connect.NewClient[healthv1.HealthCheckRequest, healthv1.HealthCheckResponse](
    97  		server.Client(),
    98  		server.URL+"/grpc.health.v1.Health/Watch",
    99  		connect.WithGRPC(),
   100  	)
   101  	stream, err := watcher.CallServerStream(
   102  		context.Background(),
   103  		connect.NewRequest(&healthv1.HealthCheckRequest{Service: userFQN}),
   104  	)
   105  	if err != nil {
   106  		t.Fatalf(err.Error())
   107  	}
   108  	defer stream.Close()
   109  	if ok := stream.Receive(); ok {
   110  		t.Fatalf("got message from Watch")
   111  	}
   112  	if stream.Err() == nil {
   113  		t.Fatalf("expected error from stream")
   114  	}
   115  	var connectErr *connect.Error
   116  	if ok := errors.As(stream.Err(), &connectErr); !ok {
   117  		t.Fatalf("got %v (%T), expected a *connect.Error", err, err)
   118  	}
   119  	if code := connectErr.Code(); code != connect.CodeUnimplemented {
   120  		t.Fatalf("got code %v, expected CodeUnimplemented", code)
   121  	}
   122  }