Skip to content

Commit 99fa6dc

Browse files
committed
tests
Signed-off-by: alanprot <[email protected]>
1 parent 6e1bfa5 commit 99fa6dc

File tree

3 files changed

+93
-4
lines changed

3 files changed

+93
-4
lines changed

pkg/cortex/modules.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"flag"
66
"fmt"
7-
"github.com/cortexproject/cortex/pkg/util/grpcclient"
87
"net/http"
98

109
"github.com/go-kit/log"
@@ -49,6 +48,7 @@ import (
4948
"github.com/cortexproject/cortex/pkg/scheduler"
5049
"github.com/cortexproject/cortex/pkg/storage/bucket"
5150
"github.com/cortexproject/cortex/pkg/storegateway"
51+
"github.com/cortexproject/cortex/pkg/util/grpcclient"
5252
util_log "github.com/cortexproject/cortex/pkg/util/log"
5353
"github.com/cortexproject/cortex/pkg/util/modules"
5454
"github.com/cortexproject/cortex/pkg/util/runtimeconfig"

pkg/util/grpcclient/health_check.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,15 @@ type HealthCheckInterceptors struct {
5353

5454
sync.RWMutex
5555
activeInstances map[string]*healthCheckEntry
56+
57+
healthClientFactory func(cc grpc.ClientConnInterface) grpc_health_v1.HealthClient
5658
}
5759

5860
func NewHealthCheckInterceptors(logger log.Logger) *HealthCheckInterceptors {
5961
h := &HealthCheckInterceptors{
60-
logger: logger,
61-
activeInstances: make(map[string]*healthCheckEntry),
62+
logger: logger,
63+
healthClientFactory: grpc_health_v1.NewHealthClient,
64+
activeInstances: make(map[string]*healthCheckEntry),
6265
}
6366

6467
h.Service = services.
@@ -105,7 +108,7 @@ func (h *HealthCheckInterceptors) iteration(ctx context.Context) error {
105108
return err
106109
}
107110
conn, err := grpc.NewClient(instance.address, dialOpts...)
108-
c := grpc_health_v1.NewHealthClient(conn)
111+
c := h.healthClientFactory(conn)
109112
if err != nil {
110113
return err
111114
}
@@ -120,6 +123,7 @@ func (h *HealthCheckInterceptors) iteration(ctx context.Context) error {
120123
if time.Since(instance.lastCheckTime.Load()) < instance.clientConfig.HealthCheckConfig.Interval {
121124
continue
122125
}
126+
instance.lastCheckTime.Store(time.Now())
123127

124128
go func(i *healthCheckEntry) {
125129
i.recordHealth(healthCheck(c, i.clientConfig.HealthCheckConfig.Timeout))
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package grpcclient
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
cortex_testutil "github.com/cortexproject/cortex/pkg/util/test"
8+
"google.golang.org/grpc"
9+
"google.golang.org/grpc/credentials/insecure"
10+
"google.golang.org/grpc/health/grpc_health_v1"
11+
"testing"
12+
"time"
13+
14+
"github.com/stretchr/testify/require"
15+
16+
utillog "github.com/cortexproject/cortex/pkg/util/log"
17+
)
18+
19+
type healthClientMock struct {
20+
grpc_health_v1.HealthClient
21+
err error
22+
}
23+
24+
func (h *healthClientMock) Check(ctx context.Context, in *grpc_health_v1.HealthCheckRequest, opts ...grpc.CallOption) (*grpc_health_v1.HealthCheckResponse, error) {
25+
return &grpc_health_v1.HealthCheckResponse{
26+
Status: grpc_health_v1.HealthCheckResponse_SERVING,
27+
}, h.err
28+
}
29+
30+
func TestNewHealthCheckInterceptors(t *testing.T) {
31+
i := NewHealthCheckInterceptors(utillog.Logger)
32+
hMock := &healthClientMock{
33+
err: fmt.Errorf("some error"),
34+
}
35+
cfg := Config{
36+
HealthCheckConfig: HealthCheckConfig{
37+
UnhealthyThreshold: 2,
38+
Interval: 0,
39+
Timeout: time.Second,
40+
},
41+
}
42+
i.healthClientFactory = func(cc grpc.ClientConnInterface) grpc_health_v1.HealthClient {
43+
return hMock
44+
}
45+
46+
ui := i.UnaryHealthCheckInterceptor(cfg)
47+
ccUnhealthy, err := grpc.NewClient("localhost:999", grpc.WithTransportCredentials(insecure.NewCredentials()))
48+
ccHealthy, err := grpc.NewClient("localhost:111", grpc.WithTransportCredentials(insecure.NewCredentials()))
49+
require.NoError(t, err)
50+
invokedMap := map[string]int{}
51+
52+
invoker := func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, opts ...grpc.CallOption) error {
53+
invokedMap[cc.Target()]++
54+
return nil
55+
}
56+
57+
//Should allow first call
58+
require.NoError(t, ui(context.Background(), "", struct{}{}, struct{}{}, ccUnhealthy, invoker))
59+
60+
// first health check
61+
i.iteration(context.Background())
62+
63+
//Should second first call
64+
require.NoError(t, ui(context.Background(), "", struct{}{}, struct{}{}, ccUnhealthy, invoker))
65+
66+
require.Equal(t, invokedMap["localhost:999"], 2)
67+
68+
// Second Healthcheck -> should mark as unhealthy
69+
i.iteration(context.Background())
70+
71+
cortex_testutil.Poll(t, time.Second, true, func() interface{} {
72+
return errors.Is(ui(context.Background(), "", struct{}{}, struct{}{}, ccUnhealthy, invoker), unhealthyErr)
73+
})
74+
75+
// Other instances should remain healthy
76+
require.NoError(t, ui(context.Background(), "", struct{}{}, struct{}{}, ccHealthy, invoker))
77+
78+
// Should mark the instance back to healthy
79+
hMock.err = nil
80+
i.iteration(context.Background())
81+
cortex_testutil.Poll(t, time.Second, true, func() interface{} {
82+
return ui(context.Background(), "", struct{}{}, struct{}{}, ccUnhealthy, invoker) == nil
83+
})
84+
85+
}

0 commit comments

Comments
 (0)