1
2
3
4
5
6
7 package writeconcern_test
8
9 import (
10 "errors"
11 "testing"
12 "time"
13
14 "go.mongodb.org/mongo-driver/bson"
15 "go.mongodb.org/mongo-driver/bson/bsontype"
16 "go.mongodb.org/mongo-driver/internal/assert"
17 "go.mongodb.org/mongo-driver/internal/require"
18 "go.mongodb.org/mongo-driver/mongo/writeconcern"
19 )
20
21 func TestWriteConcernWithOptions(t *testing.T) {
22 t.Parallel()
23
24 t.Run("on nil WriteConcern", func(t *testing.T) {
25 t.Parallel()
26
27 var wc *writeconcern.WriteConcern
28
29 wc = wc.WithOptions(writeconcern.WMajority())
30 assert.Equal(t, "majority", wc.GetW().(string))
31 assert.False(t, wc.GetJ())
32 })
33 t.Run("on existing WriteConcern", func(t *testing.T) {
34 t.Parallel()
35
36 wc := writeconcern.New(writeconcern.W(1), writeconcern.J(true))
37 assert.Equal(t, 1, wc.GetW().(int))
38 assert.True(t, wc.GetJ())
39
40 wc = wc.WithOptions(writeconcern.WMajority())
41 assert.Equal(t, "majority", wc.GetW().(string))
42 assert.True(t, wc.GetJ())
43 })
44 t.Run("with multiple options", func(t *testing.T) {
45 t.Parallel()
46
47 wc := writeconcern.New(writeconcern.W(1), writeconcern.J(true))
48 assert.Equal(t, 1, wc.GetW().(int))
49 assert.True(t, wc.GetJ())
50 assert.Equal(t, time.Duration(0), wc.GetWTimeout())
51
52 wc = wc.WithOptions(writeconcern.WMajority(), writeconcern.WTimeout(time.Second))
53 assert.Equal(t, "majority", wc.GetW().(string))
54 assert.True(t, wc.GetJ())
55 assert.Equal(t, time.Second, wc.GetWTimeout())
56 })
57 }
58
59 func TestWriteConcern_MarshalBSONValue(t *testing.T) {
60 t.Parallel()
61
62 boolPtr := func(b bool) *bool { return &b }
63
64 testCases := []struct {
65 name string
66 wc *writeconcern.WriteConcern
67 wantType bsontype.Type
68 wantValue bson.D
69 wantError error
70 }{
71 {
72 name: "all fields",
73 wc: &writeconcern.WriteConcern{
74 W: "majority",
75 Journal: boolPtr(false),
76 WTimeout: 1 * time.Minute,
77 },
78 wantType: bson.TypeEmbeddedDocument,
79 wantValue: bson.D{
80 {Key: "w", Value: "majority"},
81 {Key: "j", Value: false},
82 {Key: "wtimeout", Value: int64(60_000)},
83 },
84 },
85 {
86 name: "string W",
87 wc: &writeconcern.WriteConcern{W: "majority"},
88 wantType: bson.TypeEmbeddedDocument,
89 wantValue: bson.D{{Key: "w", Value: "majority"}},
90 },
91 {
92 name: "int W",
93 wc: &writeconcern.WriteConcern{W: 1},
94 wantType: bson.TypeEmbeddedDocument,
95 wantValue: bson.D{{Key: "w", Value: int32(1)}},
96 },
97 {
98 name: "int32 W",
99 wc: &writeconcern.WriteConcern{W: int32(1)},
100 wantError: errors.New("WriteConcern.W must be a string or int, but is a int32"),
101 },
102 {
103 name: "bool W",
104 wc: &writeconcern.WriteConcern{W: false},
105 wantError: errors.New("WriteConcern.W must be a string or int, but is a bool"),
106 },
107 {
108 name: "W=0 and J=true",
109 wc: &writeconcern.WriteConcern{W: 0, Journal: boolPtr(true)},
110 wantError: writeconcern.ErrInconsistent,
111 },
112 {
113 name: "negative W",
114 wc: &writeconcern.WriteConcern{W: -1},
115 wantError: writeconcern.ErrNegativeW,
116 },
117 {
118 name: "negative WTimeout",
119 wc: &writeconcern.WriteConcern{W: 1, WTimeout: -1},
120 wantError: writeconcern.ErrNegativeWTimeout,
121 },
122 {
123 name: "empty",
124 wc: &writeconcern.WriteConcern{},
125 wantError: writeconcern.ErrEmptyWriteConcern,
126 },
127 {
128 name: "nil",
129 wc: nil,
130 wantError: writeconcern.ErrEmptyWriteConcern,
131 },
132 }
133
134 for _, tc := range testCases {
135 tc := tc
136
137 t.Run(tc.name, func(t *testing.T) {
138 t.Parallel()
139
140 typ, b, err := tc.wc.MarshalBSONValue()
141 if tc.wantError != nil {
142 assert.Equal(t, tc.wantError, err, "expected and actual errors do not match")
143 return
144 }
145 require.NoError(t, err, "bson.MarshalValue error")
146
147 assert.Equal(t, tc.wantType, typ, "expected and actual BSON types do not match")
148
149 rv := bson.RawValue{
150 Type: typ,
151 Value: b,
152 }
153 var gotValue bson.D
154 err = rv.Unmarshal(&gotValue)
155 require.NoError(t, err, "error unmarshaling RawValue")
156 assert.Equal(t, tc.wantValue, gotValue, "expected and actual BSON values do not match")
157 })
158 }
159 }
160
161 func TestWriteConcern(t *testing.T) {
162 boolPtr := func(b bool) *bool { return &b }
163
164 testCases := []struct {
165 name string
166 wc *writeconcern.WriteConcern
167 wantAcknowledged bool
168 wantIsValid bool
169 }{
170 {
171 name: "Unacknowledged",
172 wc: writeconcern.Unacknowledged(),
173 wantAcknowledged: false,
174 wantIsValid: true,
175 },
176 {
177 name: "W1",
178 wc: writeconcern.W1(),
179 wantAcknowledged: true,
180 wantIsValid: true,
181 },
182 {
183 name: "Journaled",
184 wc: writeconcern.Journaled(),
185 wantAcknowledged: true,
186 wantIsValid: true,
187 },
188 {
189 name: "Majority",
190 wc: writeconcern.Majority(),
191 wantAcknowledged: true,
192 wantIsValid: true,
193 },
194 {
195 name: "{w: 0, j: true}",
196 wc: &writeconcern.WriteConcern{
197 W: 0,
198 Journal: boolPtr(true),
199 },
200 wantAcknowledged: true,
201 wantIsValid: false,
202 },
203 {
204 name: "{w: custom}",
205 wc: &writeconcern.WriteConcern{W: "custom"},
206 wantAcknowledged: true,
207 wantIsValid: true,
208 },
209 {
210 name: "nil",
211 wc: nil,
212 wantAcknowledged: true,
213 wantIsValid: true,
214 },
215 {
216 name: "invalid type",
217 wc: &writeconcern.WriteConcern{
218 W: struct{ Field string }{},
219 },
220 wantAcknowledged: true,
221 wantIsValid: false,
222 },
223 }
224
225 for _, tc := range testCases {
226 tc := tc
227
228 t.Run(tc.name, func(t *testing.T) {
229 t.Parallel()
230
231 assert.Equal(t,
232 tc.wantAcknowledged,
233 tc.wc.Acknowledged(),
234 "expected and actual Acknowledged value are different")
235 assert.Equal(t,
236 tc.wantIsValid,
237 tc.wc.IsValid(),
238 "expected and actual IsValid value are different")
239 })
240 }
241 }
242
View as plain text