Skip to content

Commit fc65583

Browse files
prepare 2.4.0 release (#19)
1 parent 79e0462 commit fc65583

File tree

2 files changed

+122
-42
lines changed

2 files changed

+122
-42
lines changed

ldreason/reason.go

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
"gopkg.in/launchdarkly/go-jsonstream.v1/jwriter"
1111
)
1212

13-
// EvalReasonKind defines the possible values of the Kind property of EvaluationReason.
13+
// EvalReasonKind defines the possible values of EvaluationReason.GetKind().
1414
type EvalReasonKind string
1515

1616
const (
@@ -32,7 +32,7 @@ const (
3232
EvalReasonError EvalReasonKind = "ERROR"
3333
)
3434

35-
// EvalErrorKind defines the possible values of the ErrorKind property of EvaluationReason.
35+
// EvalErrorKind defines the possible values of EvaluationReason.GetErrorKind().
3636
type EvalErrorKind string
3737

3838
const (
@@ -56,16 +56,41 @@ const (
5656
EvalErrorException EvalErrorKind = "EXCEPTION"
5757
)
5858

59+
// BigSegmentsStatus defines the possible values of EvaluationReason.GetBigSegmentsStatus().
60+
//
61+
// "Big segments" are a specific type of user segments. For more information, read the LaunchDarkly
62+
// documentation about user segments: https://docs.launchdarkly.com/home/users
63+
type BigSegmentsStatus string
64+
65+
const (
66+
// BigSegmentsHealthy indicates that the big segment query involved in the flag
67+
// evaluation was successful, and that the segment state is considered up to date.
68+
BigSegmentsHealthy BigSegmentsStatus = "HEALTHY"
69+
70+
// BigSegmentsStale indicates that the big segment query involved in the flag
71+
// evaluation was successful, but that the segment state may not be up to date.
72+
BigSegmentsStale BigSegmentsStatus = "STALE"
73+
74+
// BigSegmentsNotConfigured indicates that big segments could not be queried for the
75+
// flag evaluation because the SDK configuration did not include a big segment store.
76+
BigSegmentsNotConfigured BigSegmentsStatus = "NOT_CONFIGURED"
77+
78+
// BigSegmentsStoreError indicates that the big segment query involved in the flag
79+
// evaluation failed, for instance due to a database error.
80+
BigSegmentsStoreError BigSegmentsStatus = "STORE_ERROR"
81+
)
82+
5983
// EvaluationReason describes the reason that a flag evaluation producted a particular value.
6084
//
6185
// This struct is immutable; its properties can be accessed only via getter methods.
6286
type EvaluationReason struct {
63-
kind EvalReasonKind
64-
ruleIndex ldvalue.OptionalInt
65-
ruleID string
66-
prerequisiteKey string
67-
inExperiment bool
68-
errorKind EvalErrorKind
87+
kind EvalReasonKind
88+
ruleIndex ldvalue.OptionalInt
89+
ruleID string
90+
prerequisiteKey string
91+
inExperiment bool
92+
errorKind EvalErrorKind
93+
bigSegmentsStatus BigSegmentsStatus
6994
}
7095

7196
// IsDefined returns true if this EvaluationReason has a non-empty GetKind(). It is false for a
@@ -125,6 +150,15 @@ func (r EvaluationReason) GetErrorKind() EvalErrorKind {
125150
return r.errorKind
126151
}
127152

153+
// GetBigSegmentsStatus describes the validity of big segment information, if and only if the flag
154+
// evaluation required querying at least one big segment. Otherwise it returns an empty string.
155+
//
156+
// "Big segments" are a specific kind of user segments. For more information, read the LaunchDarkly
157+
// documentation about user segments: https://docs.launchdarkly.com/home/users
158+
func (r EvaluationReason) GetBigSegmentsStatus() BigSegmentsStatus {
159+
return r.bigSegmentsStatus
160+
}
161+
128162
// NewEvalReasonOff returns an EvaluationReason whose Kind is EvalReasonOff.
129163
func NewEvalReasonOff() EvaluationReason {
130164
return EvaluationReason{kind: EvalReasonOff}
@@ -175,6 +209,16 @@ func NewEvalReasonError(errorKind EvalErrorKind) EvaluationReason {
175209
return EvaluationReason{kind: EvalReasonError, errorKind: errorKind}
176210
}
177211

212+
// NewEvalReasonFromReasonWithBigSegmentsStatus returns a copy of an EvaluationReason
213+
// with a specific BigSegmentsStatus value added.
214+
func NewEvalReasonFromReasonWithBigSegmentsStatus(
215+
reason EvaluationReason,
216+
bigSegmentsStatus BigSegmentsStatus,
217+
) EvaluationReason {
218+
reason.bigSegmentsStatus = bigSegmentsStatus
219+
return reason
220+
}
221+
178222
// MarshalJSON implements custom JSON serialization for EvaluationReason.
179223
func (r EvaluationReason) MarshalJSON() ([]byte, error) {
180224
return jwriter.MarshalJSONWithWriter(r)
@@ -205,6 +249,8 @@ func (r *EvaluationReason) ReadFromJSONReader(reader *jreader.Reader) {
205249
ret.prerequisiteKey = reader.String()
206250
case "inExperiment":
207251
ret.inExperiment = reader.Bool()
252+
case "bigSegmentsStatus":
253+
ret.bigSegmentsStatus = BigSegmentsStatus(reader.String())
208254
}
209255
}
210256
if reader.Error() == nil {
@@ -234,6 +280,9 @@ func (r EvaluationReason) WriteToJSONWriter(w *jwriter.Writer) {
234280
if r.kind == EvalReasonError {
235281
obj.Name("errorKind").String(string(r.errorKind))
236282
}
283+
if r.bigSegmentsStatus != "" {
284+
obj.Name("bigSegmentsStatus").String(string(r.bigSegmentsStatus))
285+
}
237286
obj.End()
238287
}
239288

ldreason/reason_test.go

Lines changed: 65 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package ldreason
22

33
import (
44
"encoding/json"
5+
"strings"
56
"testing"
67

78
"gopkg.in/launchdarkly/go-jsonstream.v1/jreader"
@@ -100,12 +101,28 @@ func TestReasonErrorProperties(t *testing.T) {
100101
}
101102
}
102103

104+
func TestReasonUnboundedSegmentsStatus(t *testing.T) {
105+
for _, r := range []EvaluationReason{
106+
NewEvalReasonOff(), NewEvalReasonFallthrough(), NewEvalReasonTargetMatch(),
107+
NewEvalReasonRuleMatch(0, "id"), NewEvalReasonPrerequisiteFailed("key"),
108+
NewEvalReasonError(EvalErrorFlagNotFound),
109+
} {
110+
t.Run(string(r.GetKind()), func(t *testing.T) {
111+
assert.Equal(t, BigSegmentsStatus(""), r.GetBigSegmentsStatus())
112+
r1 := NewEvalReasonFromReasonWithBigSegmentsStatus(r, BigSegmentsHealthy)
113+
assert.Equal(t, BigSegmentsHealthy, r1.GetBigSegmentsStatus())
114+
})
115+
}
116+
}
117+
118+
type serializationTestParams struct {
119+
reason EvaluationReason
120+
stringRep string
121+
expectedJSON string
122+
}
123+
103124
func TestReasonSerializationAndDeserialization(t *testing.T) {
104-
params := []struct {
105-
reason EvaluationReason
106-
stringRep string
107-
expectedJSON string
108-
}{
125+
baseParams := []serializationTestParams{
109126
{EvaluationReason{}, "", "null"},
110127
{NewEvalReasonOff(), "OFF", `{"kind":"OFF"}`},
111128
{NewEvalReasonFallthrough(), "FALLTHROUGH", `{"kind":"FALLTHROUGH"}`},
@@ -115,38 +132,52 @@ func TestReasonSerializationAndDeserialization(t *testing.T) {
115132
{NewEvalReasonRuleMatch(1, "x"), "RULE_MATCH(1,x)", `{"kind":"RULE_MATCH","ruleIndex":1,"ruleId":"x"}`},
116133
{NewEvalReasonRuleMatchExperiment(1, "x", true), "RULE_MATCH(1,x)", `{"kind":"RULE_MATCH","ruleIndex":1,"ruleId":"x","inExperiment":true}`},
117134
{NewEvalReasonRuleMatchExperiment(1, "x", false), "RULE_MATCH(1,x)", `{"kind":"RULE_MATCH","ruleIndex":1,"ruleId":"x"}`},
118-
{NewEvalReasonPrerequisiteFailed("x"), "PREREQUISITE_FAILED(x)", `{"kind":"PREREQUISITE_FAILED","prerequisiteKey":"x"} `},
135+
{NewEvalReasonPrerequisiteFailed("x"), "PREREQUISITE_FAILED(x)", `{"kind":"PREREQUISITE_FAILED","prerequisiteKey":"x"}`},
119136
{NewEvalReasonError(EvalErrorWrongType), "ERROR(WRONG_TYPE)", `{"kind":"ERROR","errorKind":"WRONG_TYPE"}`},
120137
}
138+
params := baseParams
139+
for _, param := range baseParams {
140+
if param.reason.IsDefined() {
141+
params = append(params, serializationTestParams{
142+
reason: NewEvalReasonFromReasonWithBigSegmentsStatus(param.reason, BigSegmentsHealthy),
143+
stringRep: param.stringRep,
144+
expectedJSON: strings.TrimSuffix(param.expectedJSON, "}") +
145+
`,"bigSegmentsStatus":"HEALTHY"}`,
146+
})
147+
}
148+
}
149+
121150
for _, param := range params {
122-
actual, err := json.Marshal(param.reason)
123-
assert.NoError(t, err)
124-
assert.JSONEq(t, param.expectedJSON, string(actual))
125-
126-
var r1 EvaluationReason
127-
err = json.Unmarshal(actual, &r1)
128-
assert.NoError(t, err)
129-
assert.Equal(t, param.reason, r1)
130-
131-
assert.Equal(t, param.stringRep, param.reason.String())
132-
133-
var r2 EvaluationReason
134-
reader := jreader.NewReader(actual)
135-
r2.ReadFromJSONReader(&reader)
136-
assert.NoError(t, reader.Error())
137-
assert.Equal(t, param.reason, r2)
138-
139-
w := jwriter.NewWriter()
140-
param.reason.WriteToJSONWriter(&w)
141-
assert.NoError(t, w.Error())
142-
bytes := w.Bytes()
143-
assert.JSONEq(t, param.expectedJSON, string(bytes))
144-
145-
var buf jsonstream.JSONBuffer
146-
param.reason.WriteToJSONBuffer(&buf)
147-
bytes, err = buf.Get()
148-
assert.NoError(t, err)
149-
assert.JSONEq(t, param.expectedJSON, string(bytes))
151+
t.Run(param.expectedJSON, func(t *testing.T) {
152+
actual, err := json.Marshal(param.reason)
153+
assert.NoError(t, err)
154+
assert.JSONEq(t, param.expectedJSON, string(actual))
155+
156+
var r1 EvaluationReason
157+
err = json.Unmarshal(actual, &r1)
158+
assert.NoError(t, err)
159+
assert.Equal(t, param.reason, r1)
160+
161+
assert.Equal(t, param.stringRep, param.reason.String())
162+
163+
var r2 EvaluationReason
164+
reader := jreader.NewReader(actual)
165+
r2.ReadFromJSONReader(&reader)
166+
assert.NoError(t, reader.Error())
167+
assert.Equal(t, param.reason, r2)
168+
169+
w := jwriter.NewWriter()
170+
param.reason.WriteToJSONWriter(&w)
171+
assert.NoError(t, w.Error())
172+
bytes := w.Bytes()
173+
assert.JSONEq(t, param.expectedJSON, string(bytes))
174+
175+
var buf jsonstream.JSONBuffer
176+
param.reason.WriteToJSONBuffer(&buf)
177+
bytes, err = buf.Get()
178+
assert.NoError(t, err)
179+
assert.JSONEq(t, param.expectedJSON, string(bytes))
180+
})
150181
}
151182

152183
var r EvaluationReason

0 commit comments

Comments
 (0)