Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

prepare 2.1.0 release #13

Merged
merged 147 commits into from
Dec 14, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
147 commits
Select commit Hold shift + click to select a range
75f29a1
implement Value type for arbitrary JSON values
eli-darkly Dec 12, 2019
14cea8b
force CI rebuild
eli-darkly Dec 12, 2019
529f2a1
add go get
eli-darkly Dec 12, 2019
25fdf9e
fix go get
eli-darkly Dec 13, 2019
7478aa3
fix lint in CI
eli-darkly Dec 13, 2019
845020e
add Equal()
eli-darkly Dec 13, 2019
30fcb62
add EvaluationDetail and EvaluationReason
eli-darkly Dec 13, 2019
82923f6
fix import path
eli-darkly Dec 13, 2019
141acc1
readme fixes
eli-darkly Dec 13, 2019
0f673b0
update for v2
eli-darkly Dec 13, 2019
0342b4b
Merge branch 'v2' into eb/ch49035/detail-reason
eli-darkly Dec 13, 2019
d327ff8
fix doc comments
eli-darkly Dec 13, 2019
681a43d
add OptionalString
eli-darkly Dec 17, 2019
3220b69
misc cleanup, method renaming, better test coverage
eli-darkly Jan 23, 2020
44328ab
package comments
eli-darkly Jan 23, 2020
4cfc041
changed repo name
eli-darkly Jan 23, 2020
62437a9
numbers can't have leading decimal point
eli-darkly Jan 23, 2020
4dd29c8
Merge pull request #1 from launchdarkly/eb/ch49035/value-type
eli-darkly Jan 24, 2020
fd5ee91
actually we decided on go-sdk-common, not go-sdk-core
eli-darkly Jan 24, 2020
4a686f5
add license file
eli-darkly Jan 24, 2020
293c8b2
Merge branch 'public-v1' into v1
eli-darkly Jan 24, 2020
16fc315
OptionalString improvements + misc fixes
eli-darkly Jan 24, 2020
412e802
add OrElse
eli-darkly Jan 24, 2020
5e07050
add tests
eli-darkly Jan 24, 2020
7f9a2eb
comment
eli-darkly Jan 24, 2020
871db18
Merge branch 'v2' of github.com:launchdarkly/go-sdk-common-private in…
eli-darkly Jan 24, 2020
ec60b93
remove unsafe interface{} usage
eli-darkly Jan 24, 2020
bfb9c44
copy User and related types from go-server-sdk
eli-darkly Jan 24, 2020
7a88acd
OptionalString improvements + misc fixes (#2)
eli-darkly Jan 24, 2020
a626c5e
(common v2/SDK v5) don't use pointers or interface{}s in User
eli-darkly Jan 28, 2020
b57319b
lint
eli-darkly Jan 28, 2020
e5a23b3
lint
eli-darkly Jan 28, 2020
16c7079
Merge branch 'eb/ch58941/copy-user' into eb/ch58941/common-v2-user
eli-darkly Jan 28, 2020
312476d
rm references to obsolete function
eli-darkly Jan 28, 2020
87d4910
Merge branch 'eb/ch58941/copy-user' into eb/ch58941/common-v2-user
eli-darkly Jan 28, 2020
576fd88
(v2 - #1) copy User and related types from go-server-sdk (#3)
eli-darkly Jan 28, 2020
558a682
Merge branch 'v2' into eb/ch58941/common-v2-user
eli-darkly Jan 28, 2020
e63561b
Merge pull request #4 from launchdarkly/eb/ch58941/common-v2-user
eli-darkly Jan 28, 2020
88414be
hide all User fields, improve internal structure, add getters
eli-darkly Jan 28, 2020
b0924fd
lint
eli-darkly Jan 28, 2020
67e75cc
Merge pull request #5 from launchdarkly/eb/ch58941/hide-user-fields
eli-darkly Jan 28, 2020
a9f1f8a
Merge branch 'v1' into v2
eli-darkly Jan 29, 2020
7ccd883
Merge branch 'eb/ch63370/remove-unsafe' into eb/ch58941/user-accessors
eli-darkly Jan 29, 2020
7a480b8
add convenience methods for enumerable types
eli-darkly Jan 29, 2020
4058727
User model improvements related to custom/private attributes
eli-darkly Jan 29, 2020
6ad0ad0
lint
eli-darkly Jan 29, 2020
5db5e14
Merge branch 'v2' into eb/ch63370/remove-unsafe
eli-darkly Jan 29, 2020
8459cbe
Merge branch 'eb/ch63370/remove-unsafe' into eb/ch58941/value-enumera…
eli-darkly Jan 29, 2020
4df7f25
Merge branch 'eb/ch58941/value-enumeration' into eb/ch58941/user-acce…
eli-darkly Jan 29, 2020
2284162
Merge pull request #6 from launchdarkly/eb/ch63370/remove-unsafe
eli-darkly Jan 30, 2020
ec4cad1
Merge pull request #7 from launchdarkly/eb/ch58941/value-enumeration
eli-darkly Jan 30, 2020
3e63beb
Merge pull request #8 from launchdarkly/eb/ch58941/user-accessors
eli-darkly Jan 30, 2020
e588112
Merge branch 'public-v1' into v1
eli-darkly Feb 1, 2020
b1956fd
update release config
eli-darkly Feb 1, 2020
3f638e7
Merge branch 'public-v1' into v1
eli-darkly Feb 1, 2020
50130e8
Merge branch 'v1' into v2
eli-darkly Feb 1, 2020
7688db6
update release config
eli-darkly Feb 1, 2020
aece760
Merge branch 'public-v1' into v1
eli-darkly Feb 1, 2020
4ef5401
Merge branch 'v2' into eb/ch63866/detail-reason
eli-darkly Feb 1, 2020
256b653
fix package references
eli-darkly Feb 1, 2020
0b761e2
Merge pull request #9 from launchdarkly/eb/ch63866/detail-reason
eli-darkly Feb 3, 2020
547cd23
Merge branch 'v1' of github.com:launchdarkly/go-sdk-common into v1
eli-darkly Feb 4, 2020
065bb63
Merge branch 'v1' into v2
eli-darkly Feb 4, 2020
357513b
add ldlog package to go-sdk-common
eli-darkly Feb 4, 2020
1f08c69
lint
eli-darkly Feb 4, 2020
f7d094e
drop Go 1.8-1.11 and update linter
eli-darkly Feb 4, 2020
fb76722
gitignore
eli-darkly Feb 4, 2020
085fb8b
Merge pull request #11 from launchdarkly/eb/ch62105/drop-old-go
eli-darkly Feb 4, 2020
ebb06d6
Merge branch 'v2' into eb/ch64207/ldlog-common
eli-darkly Feb 4, 2020
0490d52
lint
eli-darkly Feb 4, 2020
08c2cf5
Merge pull request #10 from launchdarkly/eb/ch64207/ldlog-common
eli-darkly Feb 4, 2020
0e5056e
add ldtime package for time helpers
eli-darkly Feb 23, 2020
9ce753b
Merge pull request #12 from launchdarkly/eb/ch64206/time-type
eli-darkly Feb 24, 2020
ecc98c6
add Go 1.14 in CI
eli-darkly Mar 2, 2020
d551adb
Merge pull request #13 from launchdarkly/eb/ch67936/go-1.14
eli-darkly Mar 2, 2020
e9701ec
Merge branch 'v1' into v2
eli-darkly Mar 2, 2020
24c7e66
desupport Go 1.12
eli-darkly Mar 2, 2020
bdf9ef7
makefile improvement
eli-darkly Mar 2, 2020
82ce336
Merge pull request #14 from launchdarkly/eb/ch67936/no-go-1.12
eli-darkly Mar 2, 2020
e085a3a
Merge branch 'public-v2' into v2
eli-darkly Apr 1, 2020
7b18d72
make repo a module
eli-darkly Jun 4, 2020
343917d
don't install dep
eli-darkly Jun 4, 2020
6798fbe
yaml fix
eli-darkly Jun 4, 2020
0e0d49f
update golangci-lint + misc code cleanup
eli-darkly Jun 4, 2020
a9985bd
Merge branch 'eb/ch78747/linter-update' into eb/ch78731/modules
eli-darkly Jun 4, 2020
79fddc6
add methods for detecting current log level
eli-darkly Jun 4, 2020
a4bcae8
enforce consistent import groups
eli-darkly Jun 4, 2020
37676bf
enable stylecheck, fix comment
eli-darkly Jun 4, 2020
c1a52d2
add prerelease readme note
eli-darkly Jun 4, 2020
8e0ba06
Merge pull request #17 from launchdarkly/eb/ch77304/detect-debug-level
eli-darkly Jun 4, 2020
9bca369
Merge pull request #15 from launchdarkly/eb/ch78747/linter-update
eli-darkly Jun 4, 2020
09af655
Merge pull request #16 from launchdarkly/eb/ch78731/modules
eli-darkly Jun 4, 2020
3252370
Merge branch 'v2' of github.com:launchdarkly/go-sdk-common into v2
eli-darkly Jun 4, 2020
4547f29
improve test coverage and enforce coverage goals (#18)
eli-darkly Jun 11, 2020
306b165
update readme note about import path, add godoc badge
eli-darkly Jun 12, 2020
78993dd
better badge
eli-darkly Jun 12, 2020
d882b28
omit unset properties in user JSON instead of serializing null value
eli-darkly Jun 16, 2020
4c03ea3
don't allocate extra objects when setting user builder properties
eli-darkly Jun 16, 2020
5dbe2b1
Merge pull request #19 from launchdarkly/eb/ch79884/compact-user-json
eli-darkly Jun 16, 2020
c3da53a
Merge pull request #20 from launchdarkly/eb/ch77304/single-user-build…
eli-darkly Jun 16, 2020
2608fda
add generic user attr setter and more Value helper methods
eli-darkly Jun 16, 2020
d61956f
add benchmarks and enforce zero-allocation goals
eli-darkly Jun 16, 2020
5065348
Merge pull request #21 from launchdarkly/eb/ch79888/set-any-user-attr
eli-darkly Jun 16, 2020
fbe1e72
Merge pull request #22 from launchdarkly/eb/ch77270/benchmarks
eli-darkly Jun 16, 2020
467c837
implement streaming JSON serialization (#23)
eli-darkly Jun 17, 2020
ea7567b
fix bug in JSONBuffer state when writing zeroes
eli-darkly Jun 17, 2020
201d583
Merge pull request #24 from launchdarkly/eb/ch79944/jsonstream-zero-bug
eli-darkly Jun 17, 2020
503da9b
fix note about import path
eli-darkly Jun 18, 2020
2422e4e
go mod tidy
eli-darkly Jun 18, 2020
50ddf12
fix JSONBuffer string escaping, + slight refactor
eli-darkly Jun 18, 2020
0e2db4d
remove accidental inclusions from another branch
eli-darkly Jun 18, 2020
b33a319
lint
eli-darkly Jun 18, 2020
cc049b5
remove inapplicable comments
eli-darkly Jun 18, 2020
454b10c
add ability to send buffered JSON output to another writer
eli-darkly Jun 18, 2020
7aec220
Merge pull request #25 from launchdarkly/eb/ch79944/json-string-escaping
eli-darkly Jun 19, 2020
660a5ba
Merge pull request #26 from launchdarkly/eb/ch79944/stream-to-writer
eli-darkly Jun 19, 2020
2d6f974
Merge branch 'v2' of github.com:launchdarkly/go-sdk-common into v2
eli-darkly Jun 24, 2020
1bfadb3
Merge branch 'v2' of github.com:launchdarkly/go-sdk-common into v2
eli-darkly Jun 24, 2020
cc24b10
add log test helper package
eli-darkly Jun 25, 2020
2360388
Merge branch 'v2' of github.com:launchdarkly/go-sdk-common into v2
eli-darkly Jul 1, 2020
d755157
Merge pull request #27 from launchdarkly/eb/ch80986/mock-log
eli-darkly Jul 6, 2020
68c56ca
add UnmarshalText and other helper methods to OptionalString
eli-darkly Jul 6, 2020
e4e7b0f
Merge pull request #29 from launchdarkly/eb/ch81912/opt-string-parsing
eli-darkly Jul 6, 2020
290b7ab
use go-test-helpers v2 (removes unwanted eventsource dependency) (#28)
eli-darkly Jul 6, 2020
70fdf76
Merge branch 'v2' of github.com:launchdarkly/go-sdk-common into v2
eli-darkly Jul 6, 2020
cb3c12e
user unmarshaling should fail if key is missing (#30)
eli-darkly Aug 6, 2020
5191ba8
Merge branch 'v2' of github.com:launchdarkly/go-sdk-common into v2
eli-darkly Aug 6, 2020
ac7a4c2
add OptionalInt type
eli-darkly Sep 3, 2020
a383e5c
test coverage
eli-darkly Sep 3, 2020
6ff09df
keep method signature of NewEvaluationDetail the same as it used to be
eli-darkly Sep 3, 2020
bd5f1bf
comment
eli-darkly Sep 3, 2020
3dca288
Merge pull request #31 from launchdarkly/eb/ch88692/optional-int
eli-darkly Sep 3, 2020
7a1f7e4
add OptionalBool type and use it for User.Anonymous (#32)
eli-darkly Sep 3, 2020
82e9f20
add ldlogtest helper for dumping captured log output
eli-darkly Sep 3, 2020
cfcb090
Merge pull request #33 from launchdarkly/eb/ch88720/dump-log
eli-darkly Sep 8, 2020
434739c
Merge branch 'v2' of github.com:launchdarkly/go-sdk-common into v2
eli-darkly Sep 8, 2020
53178e7
add Go 1.15 build and remove beta changelog
eli-darkly Sep 18, 2020
6302689
update Go version in readme
eli-darkly Sep 18, 2020
be72603
Merge pull request #34 from launchdarkly/eb/ch89155/go-1.15
eli-darkly Sep 18, 2020
d9215ea
rm prerelease note
eli-darkly Sep 18, 2020
7556128
Merge branch 'v2' of github.com:launchdarkly/go-sdk-common into v2
eli-darkly Sep 18, 2020
21ad18b
better error reporting when unmarshaling User, OptionalString, etc. (…
eli-darkly Oct 8, 2020
50ef603
merge from public after release
LaunchDarklyCI Oct 8, 2020
7844258
add IsDefined() methods to optional-like types
eli-darkly Oct 2, 2020
f3db75e
Merge pull request #36 from launchdarkly/eb/ch91412/is-defined
eli-darkly Oct 9, 2020
b545324
better copy-on-write behavior for maps/slices; expose map & array types
eli-darkly Oct 10, 2020
1e30957
Merge pull request #37 from launchdarkly/eb/ch92116/copy-on-write
eli-darkly Oct 16, 2020
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
Prev Previous commit
Next Next commit
add EvaluationDetail and EvaluationReason
  • Loading branch information
eli-darkly committed Dec 13, 2019
commit 30fcb62fc670296857d6626c3e084f08ba206b45
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ clean:

test:
@# Note, we need to specify all these packages individually for go test in order to remain 1.8-compatible
go test -race -v ./ldvalue
go test -race -v ./ldvalue ./ldreason

$(LINTER):
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s $(GOLANGCI_LINT_VERSION)
Expand Down
42 changes: 42 additions & 0 deletions ldreason/detail.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Package ldreason provides types that describe the outcome of a LaunchDarkly flag evaluation.
//
// You do not need to use these types to evaluate feature flags with the LaunchDarkly SDK. They are
// only required for the "detail" methods that allow you to determine whether the result of a flag
// evaluation was due to, for instance, user key targeting or a specific flag rule.
package ldreason

import (
"gopkg.in/launchdarkly/go-server-sdk-core.v1/ldvalue"
)

// EvaluationDetail is an object returned by LDClient.VariationDetail, combining the result of a
// flag evaluation with an explanation of how it was calculated.
type EvaluationDetail struct {
// Value is the result of the flag evaluation. This will be either one of the flag's variations or
// the default value that was passed to the Variation method.
Value ldvalue.Value
// VariationIndex is the index of the returned value within the flag's list of variations, e.g.
// 0 for the first variation. A negative number indicates that the application default value was
// returned because the flag could not be evaluated.
VariationIndex int
// Reason is an EvaluationReason object describing the main factor that influenced the flag
// evaluation value.
Reason EvaluationReason
}

// IsDefaultValue returns true if the result of the evaluation was the application default value.
// This means that an error prevented the flag from being evaluated; the Reason field should contain
// an error value such as NewEvalReasonError(EvalErrorFlagNotFound).
func (d EvaluationDetail) IsDefaultValue() bool {
return d.VariationIndex < 0
}

// NewEvaluationDetail constructs an EvaluationDeteail, specifying all fields.
func NewEvaluationDetail(value ldvalue.Value, variationIndex int, reason EvaluationReason) EvaluationDetail {
return EvaluationDetail{Value: value, VariationIndex: variationIndex, Reason: reason}
}

// NewEvaluationDetailForError constructs an EvaluationDetail for an error condition.
func NewEvaluationDetailForError(errorKind EvalErrorKind, defaultValue ldvalue.Value) EvaluationDetail {
return EvaluationDetail{Value: defaultValue, VariationIndex: -1, Reason: NewEvalReasonError(errorKind)}
}
24 changes: 24 additions & 0 deletions ldreason/detail_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ldreason

import (
"testing"

"github.com/stretchr/testify/assert"
"gopkg.in/launchdarkly/go-server-sdk-core.v1/ldvalue"
)

func TestDetailConstructor(t *testing.T) {
detail := NewEvaluationDetail(ldvalue.Bool(true), 1, NewEvalReasonFallthrough())
assert.Equal(t, ldvalue.Bool(true), detail.Value)
assert.Equal(t, 1, detail.VariationIndex)
assert.Equal(t, NewEvalReasonFallthrough(), detail.Reason)
assert.False(t, detail.IsDefaultValue())
}

func TestDetailErrorConstructor(t *testing.T) {
detail := NewEvaluationDetailForError(EvalErrorFlagNotFound, ldvalue.Bool(false))
assert.Equal(t, ldvalue.Bool(false), detail.Value)
assert.Equal(t, -1, detail.VariationIndex)
assert.Equal(t, NewEvalReasonError(EvalErrorFlagNotFound), detail.Reason)
assert.True(t, detail.IsDefaultValue())
}
183 changes: 183 additions & 0 deletions ldreason/reason.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
package ldreason

import (
"encoding/json"
"fmt"
)

// EvalReasonKind defines the possible values of the Kind property of EvaluationReason.
type EvalReasonKind string

const (
// EvalReasonOff indicates that the flag was off and therefore returned its configured off value.
EvalReasonOff EvalReasonKind = "OFF"
// EvalReasonTargetMatch indicates that the user key was specifically targeted for this flag.
EvalReasonTargetMatch EvalReasonKind = "TARGET_MATCH"
// EvalReasonRuleMatch indicates that the user matched one of the flag's rules.
EvalReasonRuleMatch EvalReasonKind = "RULE_MATCH"
// EvalReasonPrerequisiteFailed indicates that the flag was considered off because it had at
// least one prerequisite flag that either was off or did not return the desired variation.
EvalReasonPrerequisiteFailed EvalReasonKind = "PREREQUISITE_FAILED"
// EvalReasonFallthrough indicates that the flag was on but the user did not match any targets
// or rules.
EvalReasonFallthrough EvalReasonKind = "FALLTHROUGH"
// EvalReasonError indicates that the flag could not be evaluated, e.g. because it does not
// exist or due to an unexpected error. In this case the result value will be the default value
// that the caller passed to the client.
EvalReasonError EvalReasonKind = "ERROR"
)

// EvalErrorKind defines the possible values of the ErrorKind property of EvaluationReason.
type EvalErrorKind string

const (
// EvalErrorClientNotReady indicates that the caller tried to evaluate a flag before the client
// had successfully initialized.
EvalErrorClientNotReady EvalErrorKind = "CLIENT_NOT_READY"
// EvalErrorFlagNotFound indicates that the caller provided a flag key that did not match any
// known flag.
EvalErrorFlagNotFound EvalErrorKind = "FLAG_NOT_FOUND"
// EvalErrorMalformedFlag indicates that there was an internal inconsistency in the flag data,
// e.g. a rule specified a nonexistent variation.
EvalErrorMalformedFlag EvalErrorKind = "MALFORMED_FLAG"
// EvalErrorUserNotSpecified indicates that the caller passed a user without a key for the user
// parameter.
EvalErrorUserNotSpecified EvalErrorKind = "USER_NOT_SPECIFIED"
// EvalErrorWrongType indicates that the result value was not of the requested type, e.g. you
// called BoolVariationDetail but the value was an integer.
EvalErrorWrongType EvalErrorKind = "WRONG_TYPE"
// EvalErrorException indicates that an unexpected error stopped flag evaluation; check the
// log for details.
EvalErrorException EvalErrorKind = "EXCEPTION"
)

// EvaluationReason describes the reason that a flag evaluation producted a particular value.
//
// This struct is immutable; its properties can be accessed only via getter methods.
type EvaluationReason struct {
kind EvalReasonKind
ruleIndex int
ruleID string
prerequisiteKey string
errorKind EvalErrorKind
}

// String returns a concise string representation of the reason. Examples: "OFF", "ERROR(WRONG_TYPE)".
func (r EvaluationReason) String() string {
switch r.kind {
case EvalReasonRuleMatch:
return fmt.Sprintf("%s(%d,%s)", r.kind, r.ruleIndex, r.ruleID)
case EvalReasonPrerequisiteFailed:
return fmt.Sprintf("%s(%s)", r.kind, r.prerequisiteKey)
case EvalReasonError:
return fmt.Sprintf("%s(%s)", r.kind, r.errorKind)
default:
return string(r.GetKind())
}
}

// GetKind describes the general category of the reason.
func (r EvaluationReason) GetKind() EvalReasonKind {
return r.kind
}

// GetRuleIndex provides the index of the rule that was matched (0 being the first), if
// the Kind is EvalReasonRuleMatch. Otherwise it returns -1.
func (r EvaluationReason) GetRuleIndex() int {
if r.kind == EvalReasonRuleMatch {
return r.ruleIndex
}
return -1
}

// GetRuleID provides the unique identifier of the rule that was matched, if the Kind is
// EvalReasonRuleMatch. Otherwise it returns an empty string. Unlike the rule index, this
// identifier will not change if other rules are added or deleted.
func (r EvaluationReason) GetRuleID() string {
return r.ruleID
}

// GetPrerequisiteKey provides the flag key of the prerequisite that failed, if the Kind
// is EvalReasonPrerequisiteFailed. Otherwise it returns an empty string.
func (r EvaluationReason) GetPrerequisiteKey() string {
return r.prerequisiteKey
}

// GetErrorKind describes the general category of the error, if the Kind is EvalReasonError.
// Otherwise it returns an empty string.
func (r EvaluationReason) GetErrorKind() EvalErrorKind {
return r.errorKind
}

// NewEvalReasonOff returns an EvaluationReason whose Kind is EvalReasonOff.
func NewEvalReasonOff() EvaluationReason {
return EvaluationReason{kind: EvalReasonOff}
}

// NewEvalReasonFallthrough returns an EvaluationReason whose Kind is EvalReasonFallthrough.
func NewEvalReasonFallthrough() EvaluationReason {
return EvaluationReason{kind: EvalReasonFallthrough}
}

// NewEvalReasonTargetMatch returns an EvaluationReason whose Kind is EvalReasonTargetMatch.
func NewEvalReasonTargetMatch() EvaluationReason {
return EvaluationReason{kind: EvalReasonTargetMatch}
}

// NewEvalReasonRuleMatch returns an EvaluationReason whose Kind is EvalReasonRuleMatch.
func NewEvalReasonRuleMatch(ruleIndex int, ruleID string) EvaluationReason {
return EvaluationReason{kind: EvalReasonRuleMatch, ruleIndex: ruleIndex, ruleID: ruleID}
}

// NewEvalReasonPrerequisiteFailed returns an EvaluationReason whose Kind is EvalReasonPrerequisiteFailed.
func NewEvalReasonPrerequisiteFailed(prereqKey string) EvaluationReason {
return EvaluationReason{kind: EvalReasonPrerequisiteFailed, prerequisiteKey: prereqKey}
}

// NewEvalReasonError returns an EvaluationReason whose Kind is EvalReasonError.
func NewEvalReasonError(errorKind EvalErrorKind) EvaluationReason {
return EvaluationReason{kind: EvalReasonError, errorKind: errorKind}
}

type evaluationReasonForMarshaling struct {
Kind EvalReasonKind `json:"kind"`
RuleIndex *int `json:"ruleIndex,omitempty"`
RuleID string `json:"ruleId,omitempty"`
PrerequisiteKey string `json:"prerequisiteKey,omitempty"`
ErrorKind EvalErrorKind `json:"errorKind,omitempty"`
}

// MarshalJSON implements custom JSON serialization for EvaluationReason.
func (r EvaluationReason) MarshalJSON() ([]byte, error) {
if r.kind == "" {
return []byte("null"), nil
}
erm := evaluationReasonForMarshaling{
Kind: r.kind,
RuleID: r.ruleID,
PrerequisiteKey: r.prerequisiteKey,
ErrorKind: r.errorKind,
}
if r.kind == EvalReasonRuleMatch {
erm.RuleIndex = &r.ruleIndex
}
return json.Marshal(erm)
}

// UnmarshalJSON implements custom JSON deserialization for EvaluationReason.
func (r *EvaluationReason) UnmarshalJSON(data []byte) error {
var erm evaluationReasonForMarshaling
if err := json.Unmarshal(data, &erm); err != nil {
return nil
}
*r = EvaluationReason{
kind: erm.Kind,
ruleID: erm.RuleID,
prerequisiteKey: erm.PrerequisiteKey,
errorKind: erm.ErrorKind,
}
if erm.RuleIndex != nil {
r.ruleIndex = *erm.RuleIndex
}
return nil
}
36 changes: 36 additions & 0 deletions ldreason/reason_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package ldreason

import (
"encoding/json"
"testing"

"github.com/stretchr/testify/assert"
)

func TestReasonSerializationAndDeserialization(t *testing.T) {
params := []struct {
reason EvaluationReason
stringRep string
expectedJSON string
}{
{EvaluationReason{}, "", "null"},
{NewEvalReasonOff(), "OFF", `{"kind":"OFF"}`},
{NewEvalReasonFallthrough(), "FALLTHROUGH", `{"kind":"FALLTHROUGH"}`},
{NewEvalReasonTargetMatch(), "TARGET_MATCH", `{"kind":"TARGET_MATCH"}`},
{NewEvalReasonRuleMatch(1, "x"), "RULE_MATCH(1,x)", `{"kind":"RULE_MATCH","ruleIndex":1,"ruleId":"x"}`},
{NewEvalReasonPrerequisiteFailed("x"), "PREREQUISITE_FAILED(x)", `{"kind":"PREREQUISITE_FAILED","prerequisiteKey":"x"} `},
{NewEvalReasonError(EvalErrorWrongType), "ERROR(WRONG_TYPE)", `{"kind":"ERROR","errorKind":"WRONG_TYPE"}`},
}
for _, param := range params {
actual, err := json.Marshal(param.reason)
assert.NoError(t, err)
assert.JSONEq(t, param.expectedJSON, string(actual))

var r1 EvaluationReason
err = json.Unmarshal(actual, &r1)
assert.NoError(t, err)
assert.Equal(t, param.reason, r1)

assert.Equal(t, param.stringRep, param.reason.String())
}
}