Skip to content

Commit 21806f2

Browse files
committed
handle empty/noop buffer on merge and add tests for it
1 parent eeae5c6 commit 21806f2

File tree

2 files changed

+158
-3
lines changed

2 files changed

+158
-3
lines changed

sentry/src/main/java/io/sentry/featureflags/FeatureFlagBuffer.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,12 @@ public IFeatureFlagBuffer clone() {
141141
int currentIndex = currentSize - 1;
142142

143143
@Nullable
144-
FeatureFlagEntry globalEntry = globalFlags == null ? null : globalFlags.get(globalIndex);
144+
FeatureFlagEntry globalEntry = globalFlags == null || globalIndex < 0 ? null : globalFlags.get(globalIndex);
145145
@Nullable
146146
FeatureFlagEntry isolationEntry =
147-
isolationFlags == null ? null : isolationFlags.get(isolationIndex);
147+
isolationFlags == null || isolationIndex < 0 ? null : isolationFlags.get(isolationIndex);
148148
@Nullable
149-
FeatureFlagEntry currentEntry = currentFlags == null ? null : currentFlags.get(currentIndex);
149+
FeatureFlagEntry currentEntry = currentFlags == null || currentIndex < 0 ? null : currentFlags.get(currentIndex);
150150

151151
final @NotNull java.util.Map<String, FeatureFlagEntry> uniqueFlags =
152152
new java.util.LinkedHashMap<>(maxSize);

sentry/src/test/java/io/sentry/featureflags/FeatureFlagBufferTest.kt

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,150 @@ class FeatureFlagBufferTest {
101101
assertEquals("globalC", featureFlagValues[1]!!.flag)
102102
}
103103

104+
@Test
105+
fun `when merging global buffer can be empty`() {
106+
val options = SentryOptions().also { it.maxFeatureFlags = 2 }
107+
val globalBuffer = FeatureFlagBuffer.create(options)
108+
val isolationBuffer = FeatureFlagBuffer.create(options)
109+
val currentBuffer = FeatureFlagBuffer.create(options)
110+
isolationBuffer.add("isolationA", true)
111+
currentBuffer.add("currentA", true)
112+
isolationBuffer.add("isolationB", true)
113+
currentBuffer.add("currentB", true)
114+
isolationBuffer.add("isolationC", true)
115+
currentBuffer.add("currentC", true)
116+
117+
val buffer = FeatureFlagBuffer.merged(options, globalBuffer, isolationBuffer, currentBuffer)
118+
119+
val featureFlags = buffer.featureFlags
120+
assertNotNull(featureFlags)
121+
val featureFlagValues = featureFlags.values
122+
assertEquals(2, featureFlagValues.size)
123+
124+
assertEquals("isolationC", featureFlagValues[0]!!.flag)
125+
assertEquals("currentC", featureFlagValues[1]!!.flag)
126+
}
127+
128+
@Test
129+
fun `when merging isolation buffer can be empty`() {
130+
val options = SentryOptions().also { it.maxFeatureFlags = 2 }
131+
val globalBuffer = FeatureFlagBuffer.create(options)
132+
val isolationBuffer = FeatureFlagBuffer.create(options)
133+
val currentBuffer = FeatureFlagBuffer.create(options)
134+
globalBuffer.add("globalA", true)
135+
currentBuffer.add("currentA", true)
136+
globalBuffer.add("globalB", true)
137+
currentBuffer.add("currentB", true)
138+
globalBuffer.add("globalC", true)
139+
currentBuffer.add("currentC", true)
140+
141+
val buffer = FeatureFlagBuffer.merged(options, globalBuffer, isolationBuffer, currentBuffer)
142+
143+
val featureFlags = buffer.featureFlags
144+
assertNotNull(featureFlags)
145+
val featureFlagValues = featureFlags.values
146+
assertEquals(2, featureFlagValues.size)
147+
148+
assertEquals("globalC", featureFlagValues[0]!!.flag)
149+
assertEquals("currentC", featureFlagValues[1]!!.flag)
150+
}
151+
152+
@Test
153+
fun `when merging current buffer can be empty`() {
154+
val options = SentryOptions().also { it.maxFeatureFlags = 2 }
155+
val globalBuffer = FeatureFlagBuffer.create(options)
156+
val isolationBuffer = FeatureFlagBuffer.create(options)
157+
val currentBuffer = FeatureFlagBuffer.create(options)
158+
globalBuffer.add("globalA", true)
159+
isolationBuffer.add("isolationA", true)
160+
globalBuffer.add("globalB", true)
161+
isolationBuffer.add("isolationB", true)
162+
globalBuffer.add("globalC", true)
163+
isolationBuffer.add("isolationC", true)
164+
165+
val buffer = FeatureFlagBuffer.merged(options, globalBuffer, isolationBuffer, currentBuffer)
166+
167+
val featureFlags = buffer.featureFlags
168+
assertNotNull(featureFlags)
169+
val featureFlagValues = featureFlags.values
170+
assertEquals(2, featureFlagValues.size)
171+
172+
assertEquals("globalC", featureFlagValues[0]!!.flag)
173+
assertEquals("isolationC", featureFlagValues[1]!!.flag)
174+
}
175+
176+
@Test
177+
fun `when merging global buffer can be noop`() {
178+
val options = SentryOptions().also { it.maxFeatureFlags = 2 }
179+
val globalBuffer = NoOpFeatureFlagBuffer.getInstance()
180+
val isolationBuffer = FeatureFlagBuffer.create(options)
181+
val currentBuffer = FeatureFlagBuffer.create(options)
182+
isolationBuffer.add("isolationA", true)
183+
currentBuffer.add("currentA", true)
184+
isolationBuffer.add("isolationB", true)
185+
currentBuffer.add("currentB", true)
186+
isolationBuffer.add("isolationC", true)
187+
currentBuffer.add("currentC", true)
188+
189+
val buffer = FeatureFlagBuffer.merged(options, globalBuffer, isolationBuffer, currentBuffer)
190+
191+
val featureFlags = buffer.featureFlags
192+
assertNotNull(featureFlags)
193+
val featureFlagValues = featureFlags.values
194+
assertEquals(2, featureFlagValues.size)
195+
196+
assertEquals("isolationC", featureFlagValues[0]!!.flag)
197+
assertEquals("currentC", featureFlagValues[1]!!.flag)
198+
}
199+
200+
@Test
201+
fun `when merging isolation buffer can be noop`() {
202+
val options = SentryOptions().also { it.maxFeatureFlags = 2 }
203+
val globalBuffer = FeatureFlagBuffer.create(options)
204+
val isolationBuffer = NoOpFeatureFlagBuffer.getInstance()
205+
val currentBuffer = FeatureFlagBuffer.create(options)
206+
globalBuffer.add("globalA", true)
207+
currentBuffer.add("currentA", true)
208+
globalBuffer.add("globalB", true)
209+
currentBuffer.add("currentB", true)
210+
globalBuffer.add("globalC", true)
211+
currentBuffer.add("currentC", true)
212+
213+
val buffer = FeatureFlagBuffer.merged(options, globalBuffer, isolationBuffer, currentBuffer)
214+
215+
val featureFlags = buffer.featureFlags
216+
assertNotNull(featureFlags)
217+
val featureFlagValues = featureFlags.values
218+
assertEquals(2, featureFlagValues.size)
219+
220+
assertEquals("globalC", featureFlagValues[0]!!.flag)
221+
assertEquals("currentC", featureFlagValues[1]!!.flag)
222+
}
223+
224+
@Test
225+
fun `when merging current buffer can be noop`() {
226+
val options = SentryOptions().also { it.maxFeatureFlags = 2 }
227+
val globalBuffer = FeatureFlagBuffer.create(options)
228+
val isolationBuffer = FeatureFlagBuffer.create(options)
229+
val currentBuffer = NoOpFeatureFlagBuffer.getInstance()
230+
globalBuffer.add("globalA", true)
231+
isolationBuffer.add("isolationA", true)
232+
globalBuffer.add("globalB", true)
233+
isolationBuffer.add("isolationB", true)
234+
globalBuffer.add("globalC", true)
235+
isolationBuffer.add("isolationC", true)
236+
237+
val buffer = FeatureFlagBuffer.merged(options, globalBuffer, isolationBuffer, currentBuffer)
238+
239+
val featureFlags = buffer.featureFlags
240+
assertNotNull(featureFlags)
241+
val featureFlagValues = featureFlags.values
242+
assertEquals(2, featureFlagValues.size)
243+
244+
assertEquals("globalC", featureFlagValues[0]!!.flag)
245+
assertEquals("isolationC", featureFlagValues[1]!!.flag)
246+
}
247+
104248
@Test
105249
fun `drops oldest entries when merging multiple buffers all from same source`() {
106250
val options = SentryOptions().also { it.maxFeatureFlags = 2 }
@@ -179,4 +323,15 @@ class FeatureFlagBufferTest {
179323

180324
assertTrue(buffer is NoOpFeatureFlagBuffer)
181325
}
326+
327+
@Test
328+
fun `null values are ignored`() {
329+
val buffer = FeatureFlagBuffer.create(SentryOptions().also { it.maxFeatureFlags = 2 })
330+
buffer.add(null, true)
331+
buffer.add("b", null)
332+
buffer.add(null, null)
333+
334+
val featureFlags = buffer.featureFlags
335+
assertNotNull(featureFlags)
336+
}
182337
}

0 commit comments

Comments
 (0)