Skip to content

Commit 0ab3594

Browse files
yasirfolio3Michael Ng
authored andcommitted
feat(gherkin-track): Added new steps and support for testing track API. (#156)
1 parent 5089b4d commit 0ab3594

File tree

9 files changed

+129
-24
lines changed

9 files changed

+129
-24
lines changed

tests/integration/main_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,5 @@ func FeatureContext(s *godog.Suite) {
6969
s.Step(`^the number of dispatched events is (\d+)$`, context.TheNumberOfDispatchedEventsIs)
7070
s.Step(`^there are no dispatched events$`, context.ThereAreNoDispatchedEvents)
7171
s.Step(`^dispatched events payloads include$`, context.DispatchedEventsPayloadsInclude)
72+
s.Step(`^payloads of dispatched events don\'t include decisions$`, context.PayloadsOfDispatchedEventsDontIncludeDecisions)
7273
}

tests/integration/models/api_options.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ package models
1818

1919
// APIOptions represents parameters for a scenario
2020
type APIOptions struct {
21-
APIName string
22-
Arguments string
23-
Listeners map[string]int
21+
DatafileName string
22+
APIName string
23+
Arguments string
24+
Listeners map[string]int
2425
}

tests/integration/models/constants.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ const (
5959
GetVariation SDKAPI = "get_variation"
6060
// Activate - the api type is Activate
6161
Activate SDKAPI = "activate"
62+
// Track - the api type is Track
63+
Track SDKAPI = "track"
6264
)
6365

6466
// KeyListenerCalled - Key for listener called

tests/integration/models/get_enabled_features_params.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616

1717
package models
1818

19-
// GetEnabledFeaturesParams represents params required for GetEnabledFeatures API
20-
type GetEnabledFeaturesParams struct {
19+
// GetEnabledFeaturesRequestParams represents params required for GetEnabledFeatures API
20+
type GetEnabledFeaturesRequestParams struct {
2121
UserID string `yaml:"user_id"`
2222
Attributes map[string]interface{} `yaml:"attributes"`
2323
}

tests/integration/models/get_feature_variable_params.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616

1717
package models
1818

19-
// GetFeatureVariableParams represents params required for GetFeatureVariable API's
20-
type GetFeatureVariableParams struct {
19+
// GetFeatureVariableRequestParams represents params required for GetFeatureVariable API's
20+
type GetFeatureVariableRequestParams struct {
2121
FeatureKey string `yaml:"feature_flag_key"`
2222
VariableKey string `yaml:"variable_key"`
2323
UserID string `yaml:"user_id"`

tests/integration/models/is_feature_enabled_params.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
package models
1818

19-
// IsFeatureEnabledRequestParams represents params required for isFeatureEnabled API
19+
// IsFeatureEnabledRequestParams represents params required for IsFeatureEnabled API
2020
type IsFeatureEnabledRequestParams struct {
2121
FeatureKey string `yaml:"feature_flag_key"`
2222
UserID string `yaml:"user_id"`
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/****************************************************************************
2+
* Copyright 2019, Optimizely, Inc. and contributors *
3+
* *
4+
* Licensed under the Apache License, Version 2.0 (the "License"); *
5+
* you may not use this file except in compliance with the License. *
6+
* You may obtain a copy of the License at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* Unless required by applicable law or agreed to in writing, software *
11+
* distributed under the License is distributed on an "AS IS" BASIS, *
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13+
* See the License for the specific language governing permissions and *
14+
* limitations under the License. *
15+
***************************************************************************/
16+
17+
package models
18+
19+
// TrackRequestParams represents params required for Track API
20+
type TrackRequestParams struct {
21+
EventKey string `yaml:"event_key"`
22+
UserID string `yaml:"user_id"`
23+
Attributes map[string]interface{} `yaml:"attributes"`
24+
EventTags map[string]interface{} `yaml:"event_tags,omitempty"`
25+
}

tests/integration/support/client_wrapper.go

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,27 @@ import (
3333
"gopkg.in/yaml.v3"
3434
)
3535

36+
// Map to hold clientwrapper instances against scenarioID
37+
var clientInstance *ClientWrapper
38+
3639
// ClientWrapper - wrapper around the optimizely client that keeps track of various custom components used with the client
3740
type ClientWrapper struct {
3841
Client *client.OptimizelyClient
3942
DecisionService decision.Service
4043
EventDispatcher event.Dispatcher
4144
}
4245

43-
// NewClientWrapper returns a new instance of the optly wrapper
44-
func NewClientWrapper(datafileName string) ClientWrapper {
46+
// DeleteInstance deletes cached instance of optly wrapper
47+
func DeleteInstance() {
48+
clientInstance = nil
49+
}
50+
51+
// GetInstance returns a cached or new instance of the optly wrapper
52+
func GetInstance(datafileName string) *ClientWrapper {
53+
54+
if clientInstance != nil {
55+
return clientInstance
56+
}
4557

4658
datafileDir := os.Getenv("DATAFILES_DIR")
4759
datafile, err := ioutil.ReadFile(filepath.Clean(path.Join(datafileDir, datafileName)))
@@ -74,11 +86,12 @@ func NewClientWrapper(datafileName string) ClientWrapper {
7486
log.Fatal(err)
7587
}
7688

77-
return ClientWrapper{
89+
clientInstance = &ClientWrapper{
7890
Client: client,
7991
DecisionService: decisionService,
8092
EventDispatcher: eventProcessor.EventDispatcher,
8193
}
94+
return clientInstance
8295
}
8396

8497
// InvokeAPI processes request with arguments
@@ -116,6 +129,9 @@ func (c *ClientWrapper) InvokeAPI(request models.APIOptions) (models.APIResponse
116129
case models.Activate:
117130
response, err = c.activate(request)
118131
break
132+
case models.Track:
133+
response, err = c.track(request)
134+
break
119135
default:
120136
break
121137
}
@@ -145,7 +161,7 @@ func (c *ClientWrapper) isFeatureEnabled(request models.APIOptions) (models.APIR
145161
}
146162

147163
func (c *ClientWrapper) getFeatureVariable(request models.APIOptions) (models.APIResponse, error) {
148-
var params models.GetFeatureVariableParams
164+
var params models.GetFeatureVariableRequestParams
149165
var response models.APIResponse
150166
err := yaml.Unmarshal([]byte(request.Arguments), &params)
151167
if err == nil {
@@ -163,7 +179,7 @@ func (c *ClientWrapper) getFeatureVariable(request models.APIOptions) (models.AP
163179
}
164180

165181
func (c *ClientWrapper) getFeatureVariableInteger(request models.APIOptions) (models.APIResponse, error) {
166-
var params models.GetFeatureVariableParams
182+
var params models.GetFeatureVariableRequestParams
167183
var response models.APIResponse
168184
err := yaml.Unmarshal([]byte(request.Arguments), &params)
169185
if err == nil {
@@ -180,7 +196,7 @@ func (c *ClientWrapper) getFeatureVariableInteger(request models.APIOptions) (mo
180196
}
181197

182198
func (c *ClientWrapper) getFeatureVariableDouble(request models.APIOptions) (models.APIResponse, error) {
183-
var params models.GetFeatureVariableParams
199+
var params models.GetFeatureVariableRequestParams
184200
var response models.APIResponse
185201
err := yaml.Unmarshal([]byte(request.Arguments), &params)
186202
if err == nil {
@@ -197,7 +213,7 @@ func (c *ClientWrapper) getFeatureVariableDouble(request models.APIOptions) (mod
197213
}
198214

199215
func (c *ClientWrapper) getFeatureVariableBoolean(request models.APIOptions) (models.APIResponse, error) {
200-
var params models.GetFeatureVariableParams
216+
var params models.GetFeatureVariableRequestParams
201217
var response models.APIResponse
202218
err := yaml.Unmarshal([]byte(request.Arguments), &params)
203219
if err == nil {
@@ -214,7 +230,7 @@ func (c *ClientWrapper) getFeatureVariableBoolean(request models.APIOptions) (mo
214230
}
215231

216232
func (c *ClientWrapper) getFeatureVariableString(request models.APIOptions) (models.APIResponse, error) {
217-
var params models.GetFeatureVariableParams
233+
var params models.GetFeatureVariableRequestParams
218234
var response models.APIResponse
219235
err := yaml.Unmarshal([]byte(request.Arguments), &params)
220236
if err == nil {
@@ -231,7 +247,7 @@ func (c *ClientWrapper) getFeatureVariableString(request models.APIOptions) (mod
231247
}
232248

233249
func (c *ClientWrapper) getEnabledFeatures(request models.APIOptions) (models.APIResponse, error) {
234-
var params models.GetEnabledFeaturesParams
250+
var params models.GetEnabledFeaturesRequestParams
235251
var response models.APIResponse
236252
err := yaml.Unmarshal([]byte(request.Arguments), &params)
237253
if err == nil {
@@ -281,3 +297,18 @@ func (c *ClientWrapper) activate(request models.APIOptions) (models.APIResponse,
281297
}
282298
return response, err
283299
}
300+
301+
func (c *ClientWrapper) track(request models.APIOptions) (models.APIResponse, error) {
302+
var params models.TrackRequestParams
303+
var response models.APIResponse
304+
err := yaml.Unmarshal([]byte(request.Arguments), &params)
305+
if err == nil {
306+
user := entities.UserContext{
307+
ID: params.UserID,
308+
Attributes: params.Attributes,
309+
}
310+
err = c.Client.Track(params.EventKey, user, params.EventTags)
311+
}
312+
response.Result = "NULL"
313+
return response, err
314+
}

tests/integration/support/steps.go

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"strings"
2424

2525
"github.com/DATA-DOG/godog/gherkin"
26+
"github.com/google/uuid"
2627
"github.com/optimizely/go-sdk/pkg/entities"
2728
"github.com/optimizely/go-sdk/tests/integration/models"
2829
"github.com/optimizely/go-sdk/tests/integration/optlyplugins"
@@ -32,14 +33,15 @@ import (
3233

3334
// ScenarioCtx holds both apiOptions and apiResponse for a scenario.
3435
type ScenarioCtx struct {
36+
scenarioID string
3537
apiOptions models.APIOptions
3638
apiResponse models.APIResponse
37-
clientWrapper ClientWrapper
39+
clientWrapper *ClientWrapper
3840
}
3941

4042
// TheDatafileIs defines a datafileName to initialize the client with.
4143
func (c *ScenarioCtx) TheDatafileIs(datafileName string) error {
42-
c.clientWrapper = NewClientWrapper(datafileName)
44+
c.apiOptions.DatafileName = datafileName
4345
return nil
4446
}
4547

@@ -56,6 +58,10 @@ func (c *ScenarioCtx) ListenerIsAdded(numberOfListeners int, ListenerName string
5658
func (c *ScenarioCtx) IsCalledWithArguments(apiName string, arguments *gherkin.DocString) error {
5759
c.apiOptions.APIName = apiName
5860
c.apiOptions.Arguments = arguments.Content
61+
62+
// Clearing old state of response, eventdispatcher and decision service
63+
c.apiResponse = models.APIResponse{}
64+
c.clientWrapper = GetInstance(c.apiOptions.DatafileName)
5965
response, err := c.clientWrapper.InvokeAPI(c.apiOptions)
6066
c.apiResponse = response
6167
//Reset listeners so that same listener is not added twice for a scenario
@@ -136,8 +142,13 @@ func (c *ScenarioCtx) TheResultShouldBeBoolean() error {
136142
// TheResultShouldMatchList checks that the result equals to the provided list.
137143
func (c *ScenarioCtx) TheResultShouldMatchList(list string) error {
138144
expectedList := strings.Split(list, ",")
139-
if actualList, ok := c.apiResponse.Result.([]string); ok && compareStringSlice(expectedList, actualList) {
140-
return nil
145+
if len(expectedList) == 1 && expectedList[0] == "[]" {
146+
expectedList = []string{}
147+
}
148+
if actualList, ok := c.apiResponse.Result.([]string); ok {
149+
if compareStringSlice(expectedList, actualList) {
150+
return nil
151+
}
141152
}
142153
return fmt.Errorf("incorrect result")
143154
}
@@ -211,7 +222,21 @@ func (c *ScenarioCtx) InTheResponseShouldHaveEachOneOfThese(argumentType string,
211222
if err := yaml.Unmarshal([]byte(value.Content), &requestListenersCalled); err != nil {
212223
break
213224
}
214-
if subset.Check(requestListenersCalled, c.apiResponse.ListenerCalled) {
225+
226+
found := false
227+
for _, expectedListener := range requestListenersCalled {
228+
found = false
229+
for _, actualListener := range c.apiResponse.ListenerCalled {
230+
if subset.Check(expectedListener, actualListener) {
231+
found = true
232+
break
233+
}
234+
}
235+
if !found {
236+
break
237+
}
238+
}
239+
if found {
215240
return nil
216241
}
217242
// @TODO: Revert this to test listener called
@@ -267,9 +292,29 @@ func (c *ScenarioCtx) DispatchedEventsPayloadsInclude(value *gherkin.DocString)
267292
return fmt.Errorf("DispatchedEvents not equal")
268293
}
269294

270-
// Reset clears all data before each scenario
295+
// PayloadsOfDispatchedEventsDontIncludeDecisions checks dispatched events to contain no decisions.
296+
func (c *ScenarioCtx) PayloadsOfDispatchedEventsDontIncludeDecisions() error {
297+
dispatchedEvents := c.clientWrapper.EventDispatcher.(optlyplugins.EventReceiver).GetEvents()
298+
299+
for _, event := range dispatchedEvents {
300+
for _, visitor := range event.Visitors {
301+
for _, snapshot := range visitor.Snapshots {
302+
if len(snapshot.Decisions) > 0 {
303+
return fmt.Errorf("dispatched events should not include decisions")
304+
}
305+
}
306+
}
307+
}
308+
return nil
309+
}
310+
311+
// Reset clears all data before each scenario, assigns new scenarioID and sets session as false
271312
func (c *ScenarioCtx) Reset() {
313+
// Delete cached optly wrapper instance
314+
DeleteInstance()
315+
// Clear scenario context and generate a new scenarioID
272316
c.apiOptions = models.APIOptions{}
273317
c.apiResponse = models.APIResponse{}
274-
c.clientWrapper = ClientWrapper{}
318+
c.clientWrapper = nil
319+
c.scenarioID = uuid.New().String()
275320
}

0 commit comments

Comments
 (0)