diff --git a/go.mod b/go.mod index f89cf16..15124e6 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,8 @@ go 1.19 require ( github.com/open-feature/go-sdk v1.10.0 - github.com/spotify/confidence-sdk-go/confidence v0.0.0-20240523131533-2f6be28355f0 github.com/stretchr/testify v1.9.0 + golang.org/x/text v0.14.0 ) require ( diff --git a/go.sum b/go.sum index 47b2d65..0e9c2a9 100644 --- a/go.sum +++ b/go.sum @@ -1,33 +1,18 @@ -github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0= -github.com/cucumber/godog v0.14.0/go.mod h1:FX3rzIDybWABU4kuIXLZ/qtqEe1Ac5RdXmqvACJOces= -github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/open-feature/go-sdk v1.10.0 h1:druQtYOrN+gyz3rMsXp0F2jW1oBXJb0V26PVQnUGLbM= github.com/open-feature/go-sdk v1.10.0/go.mod h1:+rkJhLBtYsJ5PZNddAgFILhRAAxwrJ32aU7UEUm4zQI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spotify/confidence-sdk-go/confidence v0.0.0-20240523131533-2f6be28355f0 h1:AumcdzoJZ7v7I4LnT0bZhNI0GTHgp8npL25LqlO3Lmo= -github.com/spotify/confidence-sdk-go/confidence v0.0.0-20240523131533-2f6be28355f0/go.mod h1:+KRet032Z5tsLOsVz+a2WN1hvz346R9atyplffpjJnM= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/pkg/confidence/EventUploader.go b/pkg/confidence/EventUploader.go index 1f37c14..87a8799 100644 --- a/pkg/confidence/EventUploader.go +++ b/pkg/confidence/EventUploader.go @@ -7,12 +7,16 @@ import ( "net/http" ) -type EventUploader struct { - client http.Client - config APIConfig +type EventUploader interface { + upload(ctx context.Context, request EventBatchRequest) } -func (e EventUploader) upload(ctx context.Context, request EventBatchRequest) { +type HttpEventUploader struct { + Client *http.Client + Config APIConfig +} + +func (e HttpEventUploader) upload(ctx context.Context, request EventBatchRequest) { jsonRequest, err := json.Marshal(request) if err != nil { return @@ -25,7 +29,7 @@ func (e EventUploader) upload(ctx context.Context, request EventBatchRequest) { return } - resp, err := e.client.Do(req) + resp, err := e.Client.Do(req) if err != nil { return } diff --git a/pkg/confidence/confidence.go b/pkg/confidence/confidence.go index d3a3766..9279cf7 100644 --- a/pkg/confidence/confidence.go +++ b/pkg/confidence/confidence.go @@ -26,7 +26,7 @@ var ( type Confidence struct { parent ContextProvider - uploader EventUploader + EventUploader EventUploader contextMap map[string]interface{} Config APIConfig ResolveClient ResolveClient @@ -69,6 +69,10 @@ func (e ConfidenceBuilder) Build() Confidence { if e.confidence.ResolveClient == nil { e.confidence.ResolveClient = HttpResolveClient{Client: &http.Client{}, Config: e.confidence.Config} } + if e.confidence.EventUploader == nil { + e.confidence.EventUploader = HttpEventUploader{Client: &http.Client{}, Config: e.confidence.Config} + } + e.confidence.contextMap = make(map[string]interface{}) return e.confidence } @@ -83,10 +87,14 @@ func (e Confidence) PutContext(key string, value interface{}) { e.contextMap[key] = value } -func (e Confidence) Track(ctx context.Context, eventName string, message map[string]interface{}) *sync.WaitGroup { - newMap := e.GetContext() +func (e Confidence) Track(ctx context.Context, eventName string, data map[string]interface{}) *sync.WaitGroup { + newMap := make(map[string]interface{}) + newMap["context"] = e.GetContext() - for key, value := range message { + for key, value := range data { + if key == "context" { + panic("invalid key \"context\" inside the data") + } newMap[key] = value } @@ -106,7 +114,7 @@ func (e Confidence) Track(ctx context.Context, eventName string, message map[str SendTime: iso8601Time, Events: []Event{event}, } - e.uploader.upload(ctx, batch) + e.EventUploader.upload(ctx, batch) wg.Done() }() return &wg diff --git a/pkg/confidence/confidence_context_test.go b/pkg/confidence/confidence_context_test.go index 3aa3f45..28c655b 100644 --- a/pkg/confidence/confidence_context_test.go +++ b/pkg/confidence/confidence_context_test.go @@ -1,11 +1,68 @@ package confidence import ( + "context" + "reflect" "testing" "github.com/stretchr/testify/assert" ) +type MockEventUploader struct { + expectedContext map[string]interface{} + TestingT *testing.T +} + +// helper function to check if a function panics +func didPanic(f func()) (didPanic bool) { + defer func() { + if r := recover(); r != nil { + didPanic = true + } + }() + f() + return +} + +func (e MockEventUploader) upload(ctx context.Context, request EventBatchRequest) { + event := request.Events[0] + assert.True(e.TestingT, reflect.DeepEqual(e.expectedContext, event.Payload["context"])) +} + +func TestContextExistsInPayload(t *testing.T) { + eventUploader := MockEventUploader{ + expectedContext: map[string]interface{}{"hello": "hey"}, + } + client := createConfidenceWithUploader(t, templateResponse(), eventUploader) + client.PutContext("hello", "hey") + wg := client.Track(context.Background(), "test", map[string]interface{}{}) + wg.Wait() +} + +func TestContextExistsInDataAndPanic(t *testing.T) { + eventUploader := MockEventUploader{ + expectedContext: map[string]interface{}{"hello": "hey"}, + } + client := createConfidenceWithUploader(t, templateResponse(), eventUploader) + client.PutContext("hello", "hey") + assert.Panics(t, func() { + wg := client.Track(context.Background(), "test", map[string]interface{}{"context": "hey"}) + wg.Wait() + }) +} + +func TestContextDoesNotExistInDataAndDoesNotPanic(t *testing.T) { + eventUploader := MockEventUploader{ + expectedContext: map[string]interface{}{"hello": "hey"}, + } + client := createConfidenceWithUploader(t, templateResponse(), eventUploader) + client.PutContext("hello", "hey") + assert.NotPanics(t, func() { + wg := client.Track(context.Background(), "test", map[string]interface{}{"not_context": "hey"}) + wg.Wait() + }) +} + func TestContextIsInConfidenceObject(t *testing.T) { client := create_confidence(t, templateResponse()) client.PutContext("hello", "hey") @@ -48,3 +105,16 @@ func create_confidence(t *testing.T, response ResolveResponse) *Confidence { contextMap: make(map[string]interface{}), } } + +func createConfidenceWithUploader(t *testing.T, response ResolveResponse, uploader MockEventUploader) *Confidence { + config := APIConfig{ + APIKey: "apiKey", + Region: APIRegionGlobal, + } + return &Confidence{ + Config: config, + EventUploader: uploader, + ResolveClient: MockResolveClient{MockedResponse: response, MockedError: nil, TestingT: t}, + contextMap: make(map[string]interface{}), + } +}