Skip to content

Commit d2e9057

Browse files
tests: add dup_faithful_copy regression for switch_event_dup
Covers the EF_UNIQ_HEADERS edge case for the O(n^2)->O(n) dup change: a well-formed EF_UNIQ source stays unique through dup, and a malformed source already holding duplicate names (only possible if headers were added before the flag was set) is copied faithfully rather than silently collapsed to the last value. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 902c7a5 commit d2e9057

1 file changed

Lines changed: 51 additions & 0 deletions

File tree

tests/unit/switch_event.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,57 @@ FST_TEST_BEGIN(dup_uniq_bench)
177177
}
178178
FST_TEST_END()
179179

180+
FST_TEST_BEGIN(dup_faithful_copy)
181+
{
182+
/* Regression for the switch_event_dup O(n^2)->O(n) change (suppressing the
183+
* per-add EF_UNIQ_HEADERS dedup scan while cloning). dup must reproduce the
184+
* source faithfully:
185+
* (1) a well-formed EF_UNIQ source stays unique through dup (the real case);
186+
* (2) a malformed source that already holds duplicate names (only possible
187+
* if headers were added before EF_UNIQ_HEADERS was set) is copied
188+
* faithfully -- dup PRESERVES the duplicates rather than silently
189+
* collapsing to the last value. A dup-bearing EF_UNIQ event is already
190+
* a bug upstream of here; a copy must not silently drop data. */
191+
switch_event_t *src = NULL, *dup = NULL;
192+
switch_event_header_t *hp;
193+
switch_status_t status;
194+
int n;
195+
196+
/* (1) well-formed EF_UNIQ source -> unique dup */
197+
status = switch_event_create(&src, SWITCH_EVENT_CHANNEL_DATA);
198+
fst_xcheck(status == SWITCH_STATUS_SUCCESS, "create CHANNEL_DATA");
199+
fst_xcheck(switch_test_flag(src, EF_UNIQ_HEADERS) != 0, "CHANNEL_DATA is EF_UNIQ");
200+
switch_event_add_header_string(src, SWITCH_STACK_BOTTOM, "k", "v1");
201+
switch_event_add_header_string(src, SWITCH_STACK_BOTTOM, "k", "v2");
202+
n = 0; for (hp = src->headers; hp; hp = hp->next) { if (!strcmp(hp->name, "k")) n++; }
203+
fst_xcheck(n == 1, "EF_UNIQ source keeps 'k' unique (collapsed to last)");
204+
status = switch_event_dup(&dup, src);
205+
fst_xcheck(status == SWITCH_STATUS_SUCCESS, "dup ok (unique)");
206+
n = 0; for (hp = dup->headers; hp; hp = hp->next) { if (!strcmp(hp->name, "k")) n++; }
207+
fst_xcheck(n == 1, "dup of unique source stays unique");
208+
fst_check_string_equals(switch_event_get_header(dup, "k"), "v2");
209+
switch_event_destroy(&dup);
210+
switch_event_destroy(&src);
211+
212+
/* (2) malformed source (duplicate names under EF_UNIQ) -> faithful copy */
213+
status = switch_event_create(&src, SWITCH_EVENT_GENERAL);
214+
fst_xcheck(status == SWITCH_STATUS_SUCCESS, "create GENERAL");
215+
fst_xcheck(switch_test_flag(src, EF_UNIQ_HEADERS) == 0, "GENERAL is not EF_UNIQ");
216+
switch_event_add_header_string(src, SWITCH_STACK_BOTTOM, "dupkey", "first");
217+
switch_event_add_header_string(src, SWITCH_STACK_BOTTOM, "dupkey", "second");
218+
switch_set_flag(src, EF_UNIQ_HEADERS);
219+
n = 0; for (hp = src->headers; hp; hp = hp->next) { if (!strcmp(hp->name, "dupkey")) n++; }
220+
fst_xcheck(n == 2, "malformed source holds 2 'dupkey' headers");
221+
status = switch_event_dup(&dup, src);
222+
fst_xcheck(status == SWITCH_STATUS_SUCCESS, "dup ok (malformed)");
223+
fst_xcheck(switch_test_flag(dup, EF_UNIQ_HEADERS) != 0, "dup keeps EF_UNIQ flag");
224+
n = 0; for (hp = dup->headers; hp; hp = hp->next) { if (!strcmp(hp->name, "dupkey")) n++; }
225+
fst_xcheck(n == 2, "dup faithfully preserves both 'dupkey' headers (no silent collapse)");
226+
switch_event_destroy(&dup);
227+
switch_event_destroy(&src);
228+
}
229+
FST_TEST_END()
230+
180231
FST_SUITE_END()
181232

182233
FST_MINCORE_END()

0 commit comments

Comments
 (0)