github.com/thanos-io/thanos@v0.32.5/pkg/rules/proxy_test.go (about)

     1  // Copyright (c) The Thanos Authors.
     2  // Licensed under the Apache License 2.0.
     3  
     4  package rules
     5  
     6  import (
     7  	"context"
     8  	"io"
     9  	"os"
    10  	"reflect"
    11  	"testing"
    12  
    13  	"github.com/go-kit/log"
    14  	"github.com/pkg/errors"
    15  	"google.golang.org/grpc"
    16  
    17  	"github.com/thanos-io/thanos/pkg/rules/rulespb"
    18  	"github.com/thanos-io/thanos/pkg/store/storepb"
    19  )
    20  
    21  type testRulesClient struct {
    22  	grpc.ClientStream
    23  	rulesErr, recvErr error
    24  	response          *rulespb.RulesResponse
    25  	sentResponse      bool
    26  }
    27  
    28  func (t *testRulesClient) String() string {
    29  	return "test"
    30  }
    31  
    32  func (t *testRulesClient) Recv() (*rulespb.RulesResponse, error) {
    33  	// A simulation of underlying grpc Recv behavior as per https://github.com/grpc/grpc-go/blob/7f2581f910fc21497091c4109b56d310276fc943/stream.go#L117-L125.
    34  	if t.recvErr != nil {
    35  		return nil, t.recvErr
    36  	}
    37  
    38  	if t.sentResponse {
    39  		return nil, io.EOF
    40  	}
    41  	t.sentResponse = true
    42  
    43  	return t.response, nil
    44  }
    45  
    46  func (t *testRulesClient) Rules(ctx context.Context, in *rulespb.RulesRequest, opts ...grpc.CallOption) (rulespb.Rules_RulesClient, error) {
    47  	return t, t.rulesErr
    48  }
    49  
    50  var _ rulespb.RulesClient = &testRulesClient{}
    51  
    52  type testRulesServer struct {
    53  	grpc.ServerStream
    54  	sendErr  error
    55  	response *rulespb.RulesResponse
    56  }
    57  
    58  func (t *testRulesServer) String() string {
    59  	return "test"
    60  }
    61  
    62  func (t *testRulesServer) Send(response *rulespb.RulesResponse) error {
    63  	if t.sendErr != nil {
    64  		return t.sendErr
    65  	}
    66  	t.response = response
    67  	return nil
    68  }
    69  
    70  func (t *testRulesServer) Context() context.Context {
    71  	return context.Background()
    72  }
    73  
    74  func TestProxy(t *testing.T) {
    75  	logger := log.NewLogfmtLogger(os.Stderr)
    76  
    77  	for _, tc := range []struct {
    78  		name         string
    79  		request      *rulespb.RulesRequest
    80  		client       rulespb.RulesClient
    81  		server       *testRulesServer
    82  		wantResponse *rulespb.RulesResponse
    83  		wantError    error
    84  	}{
    85  		{
    86  			name: "rule group proxy success",
    87  			request: &rulespb.RulesRequest{
    88  				Type:                    rulespb.RulesRequest_ALL,
    89  				PartialResponseStrategy: storepb.PartialResponseStrategy_WARN,
    90  			},
    91  			client: &testRulesClient{
    92  				response: rulespb.NewRuleGroupRulesResponse(&rulespb.RuleGroup{
    93  					Name: "foo",
    94  				}),
    95  				recvErr: nil,
    96  			},
    97  			server: &testRulesServer{},
    98  			wantResponse: rulespb.NewRuleGroupRulesResponse(&rulespb.RuleGroup{
    99  				Name: "foo",
   100  			}),
   101  		},
   102  		{
   103  			name: "warning proxy success",
   104  			request: &rulespb.RulesRequest{
   105  				Type:                    rulespb.RulesRequest_ALL,
   106  				PartialResponseStrategy: storepb.PartialResponseStrategy_WARN,
   107  			},
   108  			client: &testRulesClient{
   109  				response: rulespb.NewWarningRulesResponse(errors.New("warning from client")),
   110  				recvErr:  nil,
   111  			},
   112  			server:       &testRulesServer{},
   113  			wantResponse: rulespb.NewWarningRulesResponse(errors.New("warning from client")),
   114  		},
   115  		{
   116  			name: "warn: retreiving rules client failed",
   117  			request: &rulespb.RulesRequest{
   118  				Type:                    rulespb.RulesRequest_ALL,
   119  				PartialResponseStrategy: storepb.PartialResponseStrategy_WARN,
   120  			},
   121  			client: &testRulesClient{
   122  				response: nil,
   123  				rulesErr: errors.New("retreiving rules failed"),
   124  			},
   125  			server:       &testRulesServer{},
   126  			wantResponse: rulespb.NewWarningRulesResponse(errors.New("fetching rules from rules client test: retreiving rules failed")),
   127  		},
   128  		{
   129  			name: "warn: retreiving rules client failed, forward warning failed",
   130  			request: &rulespb.RulesRequest{
   131  				Type:                    rulespb.RulesRequest_ALL,
   132  				PartialResponseStrategy: storepb.PartialResponseStrategy_WARN,
   133  			},
   134  			client: &testRulesClient{
   135  				response: nil,
   136  				rulesErr: errors.New("retreiving rules failed"),
   137  			},
   138  			server: &testRulesServer{
   139  				sendErr: errors.New("forwarding warning response failed"),
   140  			},
   141  			wantError: errors.New("forwarding warning response failed"),
   142  		},
   143  		{
   144  			name: "abort: retreiving rules client failed",
   145  			request: &rulespb.RulesRequest{
   146  				Type:                    rulespb.RulesRequest_ALL,
   147  				PartialResponseStrategy: storepb.PartialResponseStrategy_ABORT,
   148  			},
   149  			client: &testRulesClient{
   150  				response: nil,
   151  				rulesErr: errors.New("retreiving rules failed"),
   152  			},
   153  			server:    &testRulesServer{},
   154  			wantError: errors.New("fetching rules from rules client test: retreiving rules failed"),
   155  		},
   156  		{
   157  			name: "warn: receive failed",
   158  			request: &rulespb.RulesRequest{
   159  				Type:                    rulespb.RulesRequest_ALL,
   160  				PartialResponseStrategy: storepb.PartialResponseStrategy_WARN,
   161  			},
   162  			client: &testRulesClient{
   163  				response: nil,
   164  				recvErr:  errors.New("503 from Prometheus"),
   165  			},
   166  			server:       &testRulesServer{},
   167  			wantResponse: rulespb.NewWarningRulesResponse(errors.New("receiving rules from rules client test: 503 from Prometheus")),
   168  		},
   169  		{
   170  			name: "warn: receive failed, forward warning failed",
   171  			request: &rulespb.RulesRequest{
   172  				Type:                    rulespb.RulesRequest_ALL,
   173  				PartialResponseStrategy: storepb.PartialResponseStrategy_WARN,
   174  			},
   175  			client: &testRulesClient{
   176  				response: nil,
   177  				recvErr:  errors.New("503 from Prometheus"),
   178  			},
   179  			server: &testRulesServer{
   180  				sendErr: errors.New("forwarding warning response failed"),
   181  			},
   182  			wantError: errors.New("sending rules error to server test: forwarding warning response failed"),
   183  		},
   184  		{
   185  			name: "abort: receive failed",
   186  			request: &rulespb.RulesRequest{
   187  				Type:                    rulespb.RulesRequest_ALL,
   188  				PartialResponseStrategy: storepb.PartialResponseStrategy_ABORT,
   189  			},
   190  			client: &testRulesClient{
   191  				response: nil,
   192  				recvErr:  errors.New("503 from Prometheus"),
   193  			},
   194  			server:    &testRulesServer{},
   195  			wantError: errors.New("receiving rules from rules client test: 503 from Prometheus"),
   196  		},
   197  		{
   198  			name: "send failed",
   199  			request: &rulespb.RulesRequest{
   200  				Type:                    rulespb.RulesRequest_ALL,
   201  				PartialResponseStrategy: storepb.PartialResponseStrategy_WARN,
   202  			},
   203  			client: &testRulesClient{
   204  				response: rulespb.NewRuleGroupRulesResponse(&rulespb.RuleGroup{
   205  					Name: "foo",
   206  				}),
   207  				recvErr: nil,
   208  			},
   209  			server: &testRulesServer{
   210  				sendErr: errors.New("sending message failed"),
   211  			},
   212  			wantError: errors.New("rpc error: code = Unknown desc = send rules response: sending message failed"),
   213  		},
   214  		{
   215  			name: "sending warning response failed",
   216  			request: &rulespb.RulesRequest{
   217  				Type:                    rulespb.RulesRequest_ALL,
   218  				PartialResponseStrategy: storepb.PartialResponseStrategy_WARN,
   219  			},
   220  			client: &testRulesClient{
   221  				response: rulespb.NewWarningRulesResponse(errors.New("warning from client")),
   222  				recvErr:  nil,
   223  			},
   224  			server: &testRulesServer{
   225  				sendErr: errors.New("sending message failed"),
   226  			},
   227  			wantError: errors.New("sending rules warning to server test: sending message failed"),
   228  		},
   229  	} {
   230  		t.Run(tc.name, func(t *testing.T) {
   231  			p := NewProxy(logger, func() []rulespb.RulesClient {
   232  				return []rulespb.RulesClient{tc.client}
   233  			})
   234  
   235  			err := p.Rules(tc.request, tc.server)
   236  			gotErr := "<nil>"
   237  			if err != nil {
   238  				gotErr = err.Error()
   239  			}
   240  			wantErr := "<nil>"
   241  			if tc.wantError != nil {
   242  				wantErr = tc.wantError.Error()
   243  			}
   244  
   245  			if gotErr != wantErr {
   246  				t.Errorf("want error %q, got %q", wantErr, gotErr)
   247  			}
   248  
   249  			if !reflect.DeepEqual(tc.wantResponse, tc.server.response) {
   250  				t.Errorf("want response %v, got %v", tc.wantResponse, tc.server.response)
   251  			}
   252  		})
   253  	}
   254  }
   255  
   256  // TestProxyDataRace find the concurrent data race bug ( go test -race -run TestProxyDataRace -v ).
   257  func TestProxyDataRace(t *testing.T) {
   258  	logger := log.NewLogfmtLogger(os.Stderr)
   259  	p := NewProxy(logger, func() []rulespb.RulesClient {
   260  		es := &testRulesClient{
   261  			recvErr: errors.New("err"),
   262  		}
   263  		size := 100
   264  		endpoints := make([]rulespb.RulesClient, 0, size)
   265  		for i := 0; i < size; i++ {
   266  			endpoints = append(endpoints, es)
   267  		}
   268  		return endpoints
   269  	})
   270  	req := &rulespb.RulesRequest{
   271  		Type:                    rulespb.RulesRequest_ALL,
   272  		PartialResponseStrategy: storepb.PartialResponseStrategy_WARN,
   273  	}
   274  	s := &rulesServer{
   275  		ctx: context.Background(),
   276  	}
   277  	_ = p.Rules(req, s)
   278  }