1 package ldcontext
2
3 import (
4 "encoding/json"
5 "testing"
6
7 "github.com/launchdarkly/go-sdk-common/v3/ldattr"
8 "github.com/launchdarkly/go-sdk-common/v3/lderrors"
9 "github.com/launchdarkly/go-sdk-common/v3/ldvalue"
10 "github.com/launchdarkly/go-test-helpers/v3/jsonhelpers"
11
12 "github.com/launchdarkly/go-jsonstream/v3/jwriter"
13
14 "github.com/stretchr/testify/assert"
15 "github.com/stretchr/testify/require"
16 )
17
18 type contextSerializationParams struct {
19 context Context
20 json string
21 }
22
23 func makeContextMarshalingAndUnmarshalingParams() []contextSerializationParams {
24 return []contextSerializationParams{
25 {NewWithKind("org", "key1"), `{"kind": "org", "key": "key1"}`},
26
27 {New("key1b"), `{"kind": "user", "key": "key1b"}`},
28
29 {NewBuilder("key1c").Kind("org").Build(),
30 `{"kind": "org", "key": "key1c"}`},
31
32 {NewBuilder("key2").Name("my-name").Build(),
33 `{"kind": "user", "key": "key2", "name": "my-name"}`},
34
35 {NewBuilder("key4").Anonymous(true).Build(),
36 `{"kind": "user", "key": "key4", "anonymous": true}`},
37 {NewBuilder("key5").Anonymous(false).Build(),
38 `{"kind": "user", "key": "key5"}`},
39
40 {NewBuilder("key6").SetBool("attr1", true).Build(),
41 `{"kind": "user", "key": "key6", "attr1": true}`},
42 {NewBuilder("key6").SetBool("attr1", false).Build(),
43 `{"kind": "user", "key": "key6", "attr1": false}`},
44 {NewBuilder("key6").SetInt("attr1", 123).Build(),
45 `{"kind": "user", "key": "key6", "attr1": 123}`},
46 {NewBuilder("key6").SetFloat64("attr1", 1.5).Build(),
47 `{"kind": "user", "key": "key6", "attr1": 1.5}`},
48 {NewBuilder("key6").SetString("attr1", "xyz").Build(),
49 `{"kind": "user", "key": "key6", "attr1": "xyz"}`},
50 {NewBuilder("key6").SetValue("attr1", ldvalue.ArrayOf(ldvalue.Int(10), ldvalue.Int(20))).Build(),
51 `{"kind": "user", "key": "key6", "attr1": [10, 20]}`},
52 {NewBuilder("key6").SetValue("attr1", ldvalue.ObjectBuild().Set("a", ldvalue.Int(1)).Build()).Build(),
53 `{"kind": "user", "key": "key6", "attr1": {"a": 1}}`},
54
55 {NewBuilder("key7").Private("a").PrivateRef(ldattr.NewRef("/b/c")).Build(),
56 `{"kind": "user", "key": "key7", "_meta": {"privateAttributes": ["a", "/b/c"]}}`},
57
58 {NewMulti(NewWithKind("org", "my-org-key"), New("my-user-key")),
59 `{"kind": "multi", "org": {"key": "my-org-key"}, "user": {"key": "my-user-key"}}`},
60 }
61 }
62
63 func makeContextMarshalingEventOutputFormatParams() []contextSerializationParams {
64 var ret []contextSerializationParams
65 for _, p := range makeContextMarshalingAndUnmarshalingParams() {
66 transformed := p
67 transformed.json = translateRegularContextJSONToEventOutputJSONAndViceVersa(transformed.json)
68 ret = append(ret, transformed)
69 }
70 return ret
71 }
72
73 func contextMarshalingTests(t *testing.T, marshalFn func(*Context) ([]byte, error)) {
74 for _, params := range makeContextMarshalingAndUnmarshalingParams() {
75 t.Run(params.json, func(t *testing.T) {
76 bytes, err := marshalFn(¶ms.context)
77 assert.NoError(t, err)
78 jsonhelpers.AssertEqual(t, params.json, bytes)
79 })
80 }
81
82 t.Run("invalid context", func(t *testing.T) {
83 c := New("")
84 _, err := marshalFn(&c)
85 require.Error(t, err)
86 assert.Contains(t, err.Error(), lderrors.ErrContextKeyEmpty{}.Error())
87
88
89 })
90
91 t.Run("uninitialized context", func(t *testing.T) {
92 var c Context
93 _, err := marshalFn(&c)
94 require.Error(t, err)
95 assert.Contains(t, err.Error(), lderrors.ErrContextUninitialized{}.Error())
96 })
97 }
98
99 func jsonMarshalTestFn(c *Context) ([]byte, error) {
100 return json.Marshal(c)
101 }
102
103 func jsonStreamMarshalTestFn(c *Context) ([]byte, error) {
104 w := jwriter.NewWriter()
105 ContextSerialization.MarshalToJSONWriter(&w, c)
106 return w.Bytes(), w.Error()
107 }
108
109 func TestContextJSONMarshal(t *testing.T) {
110 contextMarshalingTests(t, jsonMarshalTestFn)
111 }
112
113 func TestContextWriteToJSONWriter(t *testing.T) {
114 contextMarshalingTests(t, jsonStreamMarshalTestFn)
115 }
116
117 func TestContextMarshalEventOutputFormat(t *testing.T) {
118 for _, p := range makeContextMarshalingEventOutputFormatParams() {
119 t.Run(p.json, func(t *testing.T) {
120 w := jwriter.NewWriter()
121 ec := EventOutputContext{Context: p.context}
122 ContextSerialization.MarshalToJSONWriterEventOutput(&w, &ec)
123 assert.NoError(t, w.Error())
124 jsonhelpers.AssertEqual(t, p.json, w.Bytes())
125 })
126 }
127
128 t.Run("invalid context", func(t *testing.T) {
129 c := New("")
130 ec := EventOutputContext{Context: c}
131 w := jwriter.NewWriter()
132 ContextSerialization.MarshalToJSONWriterEventOutput(&w, &ec)
133 require.Error(t, w.Error())
134 assert.Contains(t, w.Error().Error(), lderrors.ErrContextKeyEmpty{}.Error())
135 })
136
137 t.Run("uninitialized context", func(t *testing.T) {
138 var c Context
139 ec := EventOutputContext{Context: c}
140 w := jwriter.NewWriter()
141 ContextSerialization.MarshalToJSONWriterEventOutput(&w, &ec)
142 require.Error(t, w.Error())
143 assert.Contains(t, w.Error().Error(), lderrors.ErrContextUninitialized{}.Error())
144 })
145 }
146
147 func TestContextJSONStringIsEquivalentToJSONMarshal(t *testing.T) {
148 for _, params := range makeContextMarshalingAndUnmarshalingParams() {
149 t.Run(params.json, func(t *testing.T) {
150 bytes, err := json.Marshal(¶ms.context)
151 assert.NoError(t, err)
152 jsonhelpers.AssertEqual(t, string(bytes), params.context.JSONString())
153 })
154 }
155 }
156
View as plain text