consul/agent/proxycfg-glue/resolved_service_config_tes...

120 lines
3.6 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package proxycfgglue
import (
"context"
"errors"
"fmt"
"testing"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/agent/consul/state"
"github.com/hashicorp/consul/agent/proxycfg"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/sdk/testutil"
)
func TestServerResolvedServiceConfig(t *testing.T) {
t.Run("remote queries are delegated to the remote source", func(t *testing.T) {
var (
ctx = context.Background()
req = &structs.ServiceConfigRequest{Datacenter: "dc2"}
correlationID = "correlation-id"
ch = make(chan<- proxycfg.UpdateEvent)
result = errors.New("KABOOM")
)
remoteSource := newMockResolvedServiceConfig(t)
remoteSource.On("Notify", ctx, req, correlationID, ch).Return(result)
dataSource := ServerResolvedServiceConfig(ServerDataSourceDeps{Datacenter: "dc1"}, remoteSource)
err := dataSource.Notify(ctx, req, correlationID, ch)
require.Equal(t, result, err)
})
t.Run("local queries are served from the state store", func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
const (
serviceName = "web"
datacenter = "dc1"
)
store := state.NewStateStore(nil)
nextIndex := indexGenerator()
require.NoError(t, store.EnsureConfigEntry(nextIndex(), &structs.ServiceConfigEntry{
Name: serviceName,
Protocol: "http",
}))
authz := newStaticResolver(
policyAuthorizer(t, fmt.Sprintf(`service "%s" { policy = "read" }`, serviceName)),
)
dataSource := ServerResolvedServiceConfig(ServerDataSourceDeps{
Datacenter: datacenter,
ACLResolver: authz,
GetStore: func() Store { return store },
}, nil)
eventCh := make(chan proxycfg.UpdateEvent)
require.NoError(t, dataSource.Notify(ctx, &structs.ServiceConfigRequest{Datacenter: datacenter, Name: serviceName}, "", eventCh))
testutil.RunStep(t, "initial state", func(t *testing.T) {
result := getEventResult[*structs.ServiceConfigResponse](t, eventCh)
require.Equal(t, map[string]any{"protocol": "http"}, result.ProxyConfig)
})
testutil.RunStep(t, "write proxy defaults", func(t *testing.T) {
require.NoError(t, store.EnsureConfigEntry(nextIndex(), &structs.ProxyConfigEntry{
Name: structs.ProxyConfigGlobal,
Mode: structs.ProxyModeDirect,
}))
result := getEventResult[*structs.ServiceConfigResponse](t, eventCh)
require.Equal(t, structs.ProxyModeDirect, result.Mode)
})
testutil.RunStep(t, "delete service config", func(t *testing.T) {
require.NoError(t, store.DeleteConfigEntry(nextIndex(), structs.ServiceDefaults, serviceName, nil))
result := getEventResult[*structs.ServiceConfigResponse](t, eventCh)
require.Empty(t, result.ProxyConfig)
})
testutil.RunStep(t, "revoke access", func(t *testing.T) {
authz.SwapAuthorizer(acl.DenyAll())
require.NoError(t, store.EnsureConfigEntry(nextIndex(), &structs.ServiceConfigEntry{
Name: serviceName,
Protocol: "http",
}))
expectNoEvent(t, eventCh)
})
})
}
func newMockResolvedServiceConfig(t *testing.T) *mockResolvedServiceConfig {
mock := &mockResolvedServiceConfig{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
type mockResolvedServiceConfig struct {
mock.Mock
}
func (m *mockResolvedServiceConfig) Notify(ctx context.Context, req *structs.ServiceConfigRequest, correlationID string, ch chan<- proxycfg.UpdateEvent) error {
return m.Called(ctx, req, correlationID, ch).Error(0)
}