Skip to content
Closed
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
132 changes: 132 additions & 0 deletions docs/api_docs/bundle.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,60 @@ paths:
schema:
$ref: '#/definitions/error'
/evaluation:
get:
tags:
- evaluation
operationId: getEvaluation
parameters:
- in: query
name: entity
description: >-
JSON encoded "query optimized" evaluation entity:
?entity={"id":"1","type":"a","ctx":{"foo":"bar"}}
required: true
type: string
- in: query
name: dbg
description: '"query optimized" enableDebug parameter'
type: boolean
default: false
- in: query
name: id
description: '"query optimized" flagID parameter'
required: false
type: integer
format: int64
- in: query
name: key
description: '"query optimized" flagKey parameter'
required: false
type: string
- in: query
name: tags
description: '"query optimized" flagTags parameter'
required: false
type: array
collectionFormat: csv
items:
type: string
- in: query
name: all
description: >-
whether to use ALL (flagTags) semantics (ANY by default):
`?tags=foo,bar&all=true` is equivalent to postEvaluation's
`flagTagsOperator: "ALL"`
required: false
type: boolean
default: false
responses:
'200':
description: evaluation result
schema:
$ref: '#/definitions/evalResult'
default:
description: generic error response
schema:
$ref: '#/definitions/error'
post:
tags:
- evaluation
Expand All @@ -892,6 +946,74 @@ paths:
schema:
$ref: '#/definitions/error'
/evaluation/batch:
get:
tags:
- evaluation
operationId: getEvaluationBatch
parameters:
- in: query
name: entity
description: >-
JSON encoded "query optimized" evaluation entities:
?entity={"id":"1","type":"a","ctx":{"foo":"bar"}}&entity={"id":"2","ctx":{"baz":42}}
required: true
type: array
collectionFormat: multi
minItems: 1
items:
type: string
- in: query
name: dbg
description: '"query optimized" enableDebug parameter'
required: false
type: boolean
default: false
- in: query
name: ids
description: '"query optimized" flagIDs parameter'
required: false
type: array
collectionFormat: csv
minItems: 1
items:
type: integer
format: int64
- in: query
name: keys
description: '"query optimized" flagKeys parameter'
required: false
type: array
collectionFormat: csv
minItems: 1
items:
type: string
minLength: 1
- in: query
name: tags
description: '"query optimized" flagTags parameter'
required: false
type: array
collectionFormat: csv
items:
type: string
- in: query
name: all
description: >-
whether to use ALL (flagTags) semantics (ANY by default):
`?tags=foo,bar&all=true` is equivalent to postEvaluationBatch's
`flagTagsOperator: "ALL"`
required: false
type: boolean
default: false
responses:
'200':
description: evaluation batch result
schema:
$ref: '#/definitions/evaluationBatchResponse'
default:
description: generic error response
schema:
$ref: '#/definitions/error'
post:
tags:
- evaluation
Expand Down Expand Up @@ -1396,6 +1518,16 @@ definitions:
type: string
entityContext:
type: object
getEvaluationEntity:
type: object
description: evaluationEntity's "query optimized" serialization
properties:
id:
type: string
type:
type: string
ctx:
type: object
evaluationBatchRequest:
type: object
required:
Expand Down
132 changes: 111 additions & 21 deletions pkg/handler/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (

// Eval is the Eval interface
type Eval interface {
GetEvaluation(evaluation.GetEvaluationParams) middleware.Responder
GetEvaluationBatch(evaluation.GetEvaluationBatchParams) middleware.Responder
PostEvaluation(evaluation.PostEvaluationParams) middleware.Responder
PostEvaluationBatch(evaluation.PostEvaluationBatchParams) middleware.Responder
}
Expand All @@ -34,6 +36,79 @@ func NewEval() Eval {

type eval struct{}

func (e *eval) GetEvaluation(params evaluation.GetEvaluationParams) middleware.Responder {
var evaluationEntity models.GetEvaluationEntity
err := json.Unmarshal([]byte(params.Entity), &evaluationEntity)
if err != nil {
return evaluation.NewGetEvaluationDefault(400).WithPayload(
ErrorMessage("entity in not a valid evaluation entity"))
}
flagTagsOperator := "ANY"
if params.All != nil && *params.All {
flagTagsOperator = "ALL"
}
evalContext := models.EvalContext{
EntityID: evaluationEntity.ID,
EntityType: evaluationEntity.Type,
EntityContext: evaluationEntity.Ctx,
FlagTags: params.Tags,
FlagTagsOperator: &flagTagsOperator,
}
if params.Dbg != nil && *params.Dbg {
evalContext.EnableDebug = true
}
if params.ID != nil {
evalContext.FlagID = *params.ID
}
if params.Key != nil {
evalContext.FlagKey = *params.Key
}

evalResult := EvalFlag(evalContext)
resp := evaluation.NewPostEvaluationOK()
resp.SetPayload(evalResult)
return resp
}

func (e *eval) GetEvaluationBatch(params evaluation.GetEvaluationBatchParams) middleware.Responder {
var evaluationEntities []*models.EvaluationEntity
for _, rawEntity := range params.Entity {
var getEvaluationEntity models.GetEvaluationEntity
err := json.Unmarshal([]byte(rawEntity), &getEvaluationEntity)
evaluationEntity := models.EvaluationEntity{
EntityID: getEvaluationEntity.ID,
EntityContext: getEvaluationEntity.Ctx,
EntityType: getEvaluationEntity.Type,
}
if err != nil {
return evaluation.NewGetEvaluationBatchDefault(400).WithPayload(
ErrorMessage("entity is not a valid evaluation entity: %s", rawEntity))
}
evaluationEntities = append(evaluationEntities, &evaluationEntity)
}
flagTagsOperator := "ANY"
if params.All != nil && *params.All {
flagTagsOperator = "ALL"
}
var enableDebug = false
if params.Dbg != nil && *params.Dbg {
enableDebug = true
}

results := EvaluateBatch(
evaluationEntities,
params.Ids,
params.Keys,
params.Tags,
&flagTagsOperator,
enableDebug,
)

resp := evaluation.NewPostEvaluationBatchOK()
resp.SetPayload(results)
return resp
}

func (e *eval) PostEvaluation(params evaluation.PostEvaluationParams) middleware.Responder {
evalContext := params.Body
if evalContext == nil {
Expand All @@ -48,21 +123,38 @@ func (e *eval) PostEvaluation(params evaluation.PostEvaluationParams) middleware
}

func (e *eval) PostEvaluationBatch(params evaluation.PostEvaluationBatchParams) middleware.Responder {
entities := params.Body.Entities
flagIDs := params.Body.FlagIDs
flagKeys := params.Body.FlagKeys
flagTags := params.Body.FlagTags
flagTagsOperator := params.Body.FlagTagsOperator
results := EvaluateBatch(
params.Body.Entities,
params.Body.FlagIDs,
params.Body.FlagKeys,
params.Body.FlagTags,
params.Body.FlagTagsOperator,
params.Body.EnableDebug,
)

resp := evaluation.NewPostEvaluationBatchOK()
resp.SetPayload(results)
return resp
}

func EvaluateBatch(
evaluationEntities []*models.EvaluationEntity,
flagIDs []int64,
flagKeys []string,
flagTags []string,
flagTagsOperator *string,
enableDebug bool,
) *models.EvaluationBatchResponse {
results := &models.EvaluationBatchResponse{}

// TODO make it concurrent
for _, entity := range entities {
for _, evaluationEntity := range evaluationEntities {
if len(flagTags) > 0 {
evalContext := models.EvalContext{
EnableDebug: params.Body.EnableDebug,
EntityContext: entity.EntityContext,
EntityID: entity.EntityID,
EntityType: entity.EntityType,
EnableDebug: enableDebug,
EntityContext: evaluationEntity.EntityContext,
EntityID: evaluationEntity.EntityID,
EntityType: evaluationEntity.EntityType,
FlagTags: flagTags,
FlagTagsOperator: flagTagsOperator,
}
Expand All @@ -71,10 +163,10 @@ func (e *eval) PostEvaluationBatch(params evaluation.PostEvaluationBatchParams)
}
for _, flagID := range flagIDs {
evalContext := models.EvalContext{
EnableDebug: params.Body.EnableDebug,
EntityContext: entity.EntityContext,
EntityID: entity.EntityID,
EntityType: entity.EntityType,
EnableDebug: enableDebug,
EntityContext: evaluationEntity.EntityContext,
EntityID: evaluationEntity.EntityID,
EntityType: evaluationEntity.EntityType,
FlagID: flagID,
}

Expand All @@ -83,10 +175,10 @@ func (e *eval) PostEvaluationBatch(params evaluation.PostEvaluationBatchParams)
}
for _, flagKey := range flagKeys {
evalContext := models.EvalContext{
EnableDebug: params.Body.EnableDebug,
EntityContext: entity.EntityContext,
EntityID: entity.EntityID,
EntityType: entity.EntityType,
EnableDebug: enableDebug,
EntityContext: evaluationEntity.EntityContext,
EntityID: evaluationEntity.EntityID,
EntityType: evaluationEntity.EntityType,
FlagKey: flagKey,
}

Expand All @@ -95,9 +187,7 @@ func (e *eval) PostEvaluationBatch(params evaluation.PostEvaluationBatchParams)
}
}

resp := evaluation.NewPostEvaluationBatchOK()
resp.SetPayload(results)
return resp
return results
}

// BlankResult creates a blank result
Expand Down
40 changes: 40 additions & 0 deletions pkg/handler/eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,46 @@ func TestEvalFlagsByTags(t *testing.T) {
})
}

func TestGetEvaluation(t *testing.T) {
t.Run("test empty query", func(t *testing.T) {
defer gostub.StubFunc(&EvalFlag, &models.EvalResult{}).Reset()
e := NewEval()
resp := e.GetEvaluation(evaluation.GetEvaluationParams{})
assert.NotNil(t, resp)
})

t.Run("test happy code path", func(t *testing.T) {
defer gostub.StubFunc(&EvalFlag, &models.EvalResult{}).Reset()
e := NewEval()
enableDebug := true
flagID := int64(100)
resp := e.GetEvaluation(evaluation.GetEvaluationParams{
Entity: "{\"id\":\"entityID1\",\"type\":\"entityType1\",\"ctx\":{\"dl_state\":\"CA\",\"state\":\"NY\"}}",
ID: &flagID,
Dbg: &enableDebug,
})
assert.NotNil(t, resp)
})
}

func TestGetEvaluationBatch(t *testing.T) {
t.Run("test happy code path", func(t *testing.T) {
defer gostub.StubFunc(&EvalFlag, &models.EvalResult{}).Reset()
e := NewEval()
enableDebug := true
resp := e.GetEvaluationBatch(evaluation.GetEvaluationBatchParams{
Dbg: &enableDebug,
Entity: []string{
"{\"id\":\"entityID1\",\"type\":\"entityType1\",\"ctx\":{\"dl_state\":\"CA\",\"state\":\"NY\"}}",
"{\"id\":\"entityID2\",\"type\":\"entityType2\",\"ctx\":{\"dl_state\":\"CA\",\"state\":\"NY\"}}",
},
Ids: []int64{100, 200},
Keys: []string{"flag_key_1", "flag_key_2"},
})
assert.NotNil(t, resp)
})
}

func TestPostEvaluation(t *testing.T) {
t.Run("test empty body", func(t *testing.T) {
defer gostub.StubFunc(&EvalFlag, &models.EvalResult{}).Reset()
Expand Down
2 changes: 2 additions & 0 deletions pkg/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ func setupEvaluation(api *operations.FlagrAPI) {
ec.Start()

e := NewEval()
api.EvaluationGetEvaluationHandler = evaluation.GetEvaluationHandlerFunc(e.GetEvaluation)
api.EvaluationGetEvaluationBatchHandler = evaluation.GetEvaluationBatchHandlerFunc(e.GetEvaluationBatch)
api.EvaluationPostEvaluationHandler = evaluation.PostEvaluationHandlerFunc(e.PostEvaluation)
api.EvaluationPostEvaluationBatchHandler = evaluation.PostEvaluationBatchHandlerFunc(e.PostEvaluationBatch)

Expand Down
Loading
Loading