consul/agent/rpc/operator/service_test.go
Dhia Ayachi 225ae55e83
Leadership transfer cmd (#14132)
* add leadership transfer command

* add RPC call test (flaky)

* add missing import

* add changelog

* add command registration

* Apply suggestions from code review

Co-authored-by: Matt Keeler <mkeeler@users.noreply.github.com>

* add the possibility of providing an id to raft leadership transfer. Add few tests.

* delete old file from cherry pick

* rename changelog filename to PR #

* rename changelog and fix import

* fix failing test

* check for OperatorWrite

Co-authored-by: Matt Keeler <mkeeler@users.noreply.github.com>

* rename from leader-transfer to transfer-leader

* remove version check and add test for operator read

* move struct to operator.go

* first pass

* add code for leader transfer in the grpc backend and tests

* wire the http endpoint to the new grpc endpoint

* remove the RPC endpoint

* remove non needed struct

* fix naming

* add mog glue to API

* fix comment

* remove dead code

* fix linter error

* change package name for proto file

* remove error wrapping

* fix failing test

* add command registration

* add grpc service mock tests

* fix receiver to be pointer

* use defined values

Co-authored-by: Matt Keeler <mkeeler@users.noreply.github.com>

* reuse MockAclAuthorizer

* add documentation

* remove usage of external.TokenFromContext

* fix failing tests

* fix proto generation

* Apply suggestions from code review

Co-authored-by: Jared Kirschner <85913323+jkirschner-hashicorp@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Jared Kirschner <85913323+jkirschner-hashicorp@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Jared Kirschner <85913323+jkirschner-hashicorp@users.noreply.github.com>

* Apply suggestions from code review

* add more context in doc for the reason

* Apply suggestions from docs code review

Co-authored-by: Jeff Boruszak <104028618+boruszak@users.noreply.github.com>

* regenerate proto

* fix linter errors

Co-authored-by: github-team-consul-core <github-team-consul-core@hashicorp.com>
Co-authored-by: Matt Keeler <mkeeler@users.noreply.github.com>
Co-authored-by: Jared Kirschner <85913323+jkirschner-hashicorp@users.noreply.github.com>
Co-authored-by: Jeff Boruszak <104028618+boruszak@users.noreply.github.com>
2022-11-14 15:35:12 -05:00

105 lines
3.9 KiB
Go

package operator
import (
"context"
"fmt"
"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/acl/resolver"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/proto/pboperator"
"github.com/hashicorp/go-hclog"
"github.com/stretchr/testify/mock"
"google.golang.org/grpc"
"testing"
"github.com/stretchr/testify/require"
)
type MockBackend struct {
mock.Mock
authorizer acl.Authorizer
}
func (m *MockBackend) TransferLeader(ctx context.Context, request *pboperator.TransferLeaderRequest) (*pboperator.TransferLeaderResponse, error) {
called := m.Called(ctx, request)
ret := called.Get(0)
if ret == nil {
return nil, called.Error(1)
}
return ret.(*pboperator.TransferLeaderResponse), called.Error(1)
}
func (m *MockBackend) ResolveTokenAndDefaultMeta(token string, entMeta *acl.EnterpriseMeta, authzCtx *acl.AuthorizerContext) (resolver.Result, error) {
return resolver.Result{Authorizer: m.authorizer}, nil
}
func TestLeaderTransfer_ACL_Deny(t *testing.T) {
authorizer := acl.MockAuthorizer{}
authorizer.On("OperatorWrite", mock.Anything).Return(acl.Deny)
server := NewServer(Config{Datacenter: "dc1", Backend: &MockBackend{authorizer: &authorizer}, Logger: hclog.New(nil), ForwardRPC: doForwardRPC})
_, err := server.TransferLeader(context.Background(), &pboperator.TransferLeaderRequest{})
require.Error(t, err)
require.Equal(t, "Permission denied: provided token lacks permission 'operator:write'", err.Error())
}
func TestLeaderTransfer_ACL_Allowed(t *testing.T) {
authorizer := &acl.MockAuthorizer{}
authorizer.On("OperatorWrite", mock.Anything).Return(acl.Allow)
backend := &MockBackend{authorizer: authorizer}
backend.On("TransferLeader", mock.Anything, mock.Anything).Return(nil, nil)
server := NewServer(Config{Datacenter: "dc1", Backend: backend, Logger: hclog.New(nil), ForwardRPC: doForwardRPC})
_, err := server.TransferLeader(context.Background(), &pboperator.TransferLeaderRequest{})
require.NoError(t, err)
}
func TestLeaderTransfer_LeaderTransfer_Fail(t *testing.T) {
authorizer := &acl.MockAuthorizer{}
authorizer.On("OperatorWrite", mock.Anything).Return(acl.Allow)
backend := &MockBackend{authorizer: authorizer}
backend.On("TransferLeader", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("test"))
server := NewServer(Config{Datacenter: "dc1", Backend: backend, Logger: hclog.New(nil), ForwardRPC: doForwardRPC})
_, err := server.TransferLeader(context.Background(), &pboperator.TransferLeaderRequest{})
require.Error(t, err)
require.Equal(t, "test", err.Error())
}
func TestLeaderTransfer_LeaderTransfer_Success(t *testing.T) {
authorizer := &acl.MockAuthorizer{}
authorizer.On("OperatorWrite", mock.Anything).Return(acl.Allow)
backend := &MockBackend{authorizer: authorizer}
backend.On("TransferLeader", mock.Anything, mock.Anything).Return(&pboperator.TransferLeaderResponse{Success: true}, nil)
server := NewServer(Config{Datacenter: "dc1", Backend: backend, Logger: hclog.New(nil), ForwardRPC: doForwardRPC})
ret, err := server.TransferLeader(context.Background(), &pboperator.TransferLeaderRequest{})
require.NoError(t, err)
require.NotNil(t, ret)
require.True(t, ret.Success)
}
func TestLeaderTransfer_LeaderTransfer_ForwardRPC(t *testing.T) {
authorizer := &acl.MockAuthorizer{}
authorizer.On("OperatorWrite", mock.Anything).Return(acl.Allow)
backend := &MockBackend{authorizer: authorizer}
backend.On("TransferLeader", mock.Anything, mock.Anything).Return(&pboperator.TransferLeaderResponse{}, nil)
server := NewServer(Config{Datacenter: "dc1", Backend: backend, Logger: hclog.New(nil), ForwardRPC: noopForwardRPC})
ret, err := server.TransferLeader(context.Background(), &pboperator.TransferLeaderRequest{})
require.NoError(t, err)
require.NotNil(t, ret)
require.False(t, ret.Success)
}
func noopForwardRPC(structs.RPCInfo, func(*grpc.ClientConn) error) (bool, error) {
return true, nil
}
func doForwardRPC(structs.RPCInfo, func(*grpc.ClientConn) error) (bool, error) {
return false, nil
}