Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion providers/flagd/pkg/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ package flagd
import (
"errors"
"fmt"
"net/http"
"os"
"strconv"
"strings"

"github.com/go-logr/logr"
"github.com/open-feature/flagd/core/pkg/sync"
"google.golang.org/grpc"

"github.com/open-feature/go-sdk-contrib/providers/flagd/internal/cache"
"github.com/open-feature/go-sdk-contrib/providers/flagd/internal/logger"
"google.golang.org/grpc"
)

type ResolverType string
Expand Down Expand Up @@ -70,6 +72,7 @@ type ProviderConfiguration struct {
GrpcDialOptionsOverride []grpc.DialOption
RetryGracePeriod int
FatalStatusCodes []string
HTTPClient *http.Client

log logr.Logger
}
Expand Down Expand Up @@ -437,4 +440,12 @@ func WithFatalStatusCodes(fatalStatusCodes []string) ProviderOption {
return func(p *ProviderConfiguration) {
p.FatalStatusCodes = fatalStatusCodes
}

}

// WithHTTPClient allows to set a custom HTTP client for the provider.
func WithHTTPClient(client *http.Client) ProviderOption {
return func(p *ProviderConfiguration) {
p.HTTPClient = client
}
}
17 changes: 17 additions & 0 deletions providers/flagd/pkg/configuration_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package flagd

import (
"net/http"
"testing"
)

Expand Down Expand Up @@ -64,3 +65,19 @@ func TestValidateProviderConfigurationFileMissingData(t *testing.T) {
t.Errorf("Error expected but check succeeded")
}
}

func TestConfigureProviderConfigurationWithoutHTTPClient(t *testing.T) {
httpClient := http.Client{}
// given
providerConfiguration := &ProviderConfiguration{
HTTPClient: &httpClient,
}

// when
configureProviderConfiguration(providerConfiguration)

// then
if providerConfiguration.HTTPClient != &httpClient {
t.Errorf("incorrect HTTPClient, expected %v, got %v", httpClient, providerConfiguration.HTTPClient)
}
}
5 changes: 3 additions & 2 deletions providers/flagd/pkg/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ package flagd
import (
"context"
"fmt"

parallel "sync"

of "github.com/open-feature/go-sdk/openfeature"

"github.com/open-feature/go-sdk-contrib/providers/flagd/internal/cache"
process "github.com/open-feature/go-sdk-contrib/providers/flagd/pkg/service/in_process"
rpcService "github.com/open-feature/go-sdk-contrib/providers/flagd/pkg/service/rpc"
of "github.com/open-feature/go-sdk/openfeature"
)

const (
Expand Down Expand Up @@ -56,6 +56,7 @@ func NewProvider(opts ...ProviderOption) (*Provider, error) {
SocketPath: provider.providerConfiguration.SocketPath,
TLSEnabled: provider.providerConfiguration.Tls,
OtelInterceptor: provider.providerConfiguration.OtelIntercept,
HTTPClient: provider.providerConfiguration.HTTPClient,
},
cacheService,
provider.providerConfiguration.log,
Expand Down
17 changes: 14 additions & 3 deletions providers/flagd/pkg/provider_test.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package flagd

import (
"net/http"
"reflect"
"testing"

"github.com/open-feature/flagd/core/pkg/sync"
"github.com/open-feature/go-sdk-contrib/providers/flagd/internal/cache"
"github.com/open-feature/go-sdk-contrib/providers/flagd/internal/mock"
process "github.com/open-feature/go-sdk-contrib/providers/flagd/pkg/service/in_process"
of "github.com/open-feature/go-sdk/openfeature"
"go.uber.org/mock/gomock"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"

"github.com/open-feature/go-sdk-contrib/providers/flagd/internal/cache"
"github.com/open-feature/go-sdk-contrib/providers/flagd/internal/mock"
process "github.com/open-feature/go-sdk-contrib/providers/flagd/pkg/service/in_process"
)

func TestNewProvider(t *testing.T) {
Expand All @@ -21,6 +23,7 @@ func TestNewProvider(t *testing.T) {
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithAuthority("test-authority"),
}
httpClientOverride := http.Client{}

tests := []struct {
name string
Expand All @@ -41,6 +44,7 @@ func TestNewProvider(t *testing.T) {
expectCustomSyncProviderUri string
expectOfflineFlagSourcePath string
expectGrpcDialOptionsOverride []grpc.DialOption
expectedHTTPClientOverride *http.Client
options []ProviderOption
}{
{
Expand Down Expand Up @@ -74,6 +78,7 @@ func TestNewProvider(t *testing.T) {
expectTlsEnabled: true,
expectCustomSyncProvider: nil,
expectCustomSyncProviderUri: "",
expectedHTTPClientOverride: &httpClientOverride,
options: []ProviderOption{
WithInProcessResolver(),
WithSocketPath("/socket"),
Expand All @@ -83,6 +88,7 @@ func TestNewProvider(t *testing.T) {
WithCertificatePath("/path"),
WithHost("myHost"),
WithPort(9090),
WithHTTPClient(&httpClientOverride),
},
},
{
Expand Down Expand Up @@ -357,6 +363,11 @@ func TestNewProvider(t *testing.T) {
test.expectOfflineFlagSourcePath, config.OfflineFlagSourcePath)
}

if config.HTTPClient != test.expectedHTTPClientOverride {
t.Errorf("incorrect configuration HTTPClient, expected %v, got %v",
test.expectedHTTPClientOverride, config.HTTPClient)
}

if test.expectGrpcDialOptionsOverride != nil {
if config.GrpcDialOptionsOverride == nil {
t.Errorf("incorrent configuration GrpcDialOptionsOverride, expected %v, got nil", config.GrpcDialOptionsOverride)
Expand Down
25 changes: 16 additions & 9 deletions providers/flagd/pkg/service/rpc/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ import (
"github.com/go-logr/logr"
flagdModels "github.com/open-feature/flagd/core/pkg/model"
flagdService "github.com/open-feature/flagd/core/pkg/service"
"github.com/open-feature/go-sdk-contrib/providers/flagd/internal/cache"
"github.com/open-feature/go-sdk-contrib/providers/flagd/internal/logger"
of "github.com/open-feature/go-sdk/openfeature"
"golang.org/x/net/context"
"google.golang.org/protobuf/types/known/structpb"

"github.com/open-feature/go-sdk-contrib/providers/flagd/internal/cache"
"github.com/open-feature/go-sdk-contrib/providers/flagd/internal/logger"
)

const (
Expand All @@ -39,6 +40,7 @@ type Configuration struct {
SocketPath string
TLSEnabled bool
OtelInterceptor bool
HTTPClient *http.Client
}

// Service handles the client side interface for the flagd server
Expand Down Expand Up @@ -452,7 +454,7 @@ func (s *Service) EventChannel() <-chan of.Event {
// If retrying is exhausted, an event with openfeature.ProviderError will be emitted.
func (s *Service) startEventStream(ctx context.Context) {
streamReadySignaled := false

// wraps connection with retry attempts
for s.retryCounter.retry() {
s.logger.V(logger.Debug).Info("connecting to event stream")
Expand Down Expand Up @@ -488,12 +490,12 @@ func (s *Service) startEventStream(ctx context.Context) {
// retry attempts exhausted. Disable cache and emit error event
s.cache.Disable()
connErr := fmt.Errorf("grpc connection establishment failed")

// Signal error if we haven't signaled success yet
if !streamReadySignaled {
s.signalStreamReady(connErr)
}

s.sendEvent(ctx, of.Event{
ProviderName: "flagd",
EventType: of.ProviderError,
Expand Down Expand Up @@ -521,7 +523,7 @@ func (s *Service) streamClient(ctx context.Context, streamReadySignaled *bool) e
}

s.logger.V(logger.Info).Info("connected to event stream")

// Signal successful connection to Init() - stream is now ready
if !*streamReadySignaled {
s.signalStreamReady(nil) // nil means success
Expand Down Expand Up @@ -657,13 +659,18 @@ func newClient(cfg Configuration) (schemaConnectV1.ServiceClient, error) {
options = append(options, connect.WithInterceptors(interceptor))
}

return schemaConnectV1.NewServiceClient(
&http.Client{
httpClient := cfg.HTTPClient
if httpClient == nil {
httpClient = &http.Client{
Transport: &http.Transport{
TLSClientConfig: tlsConfig,
DialContext: dialContext,
},
},
}
}

return schemaConnectV1.NewServiceClient(
httpClient,
url,
options...,
), nil
Expand Down