diff options
author | Alessandro Decina <alessandro.decina@collabora.co.uk> | 2010-08-12 15:53:42 +0200 |
---|---|---|
committer | Alessandro Decina <alessandro.decina@collabora.co.uk> | 2010-08-20 10:31:38 +0200 |
commit | 32fa1002d03f6e291265c04bcd3bf82f5101671c (patch) | |
tree | 86abd2b3ef4106d93b9d36509e71ca96dd085ebc | |
parent | 00b4bfa48f23e671b40c36e428ebfc224f0e3c9c (diff) |
tests: add a test case for a race in gnlcomposition. See #626733.
Add a test for a race between no_more_objects_cb and compare_relink_single_node
in gnlcomposition.
-rw-r--r-- | tests/check/gnl/gnlcomposition.c | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/tests/check/gnl/gnlcomposition.c b/tests/check/gnl/gnlcomposition.c index 9063a1c..cf22fa0 100644 --- a/tests/check/gnl/gnlcomposition.c +++ b/tests/check/gnl/gnlcomposition.c | |||
@@ -18,6 +18,12 @@ | |||
18 | */ | 18 | */ |
19 | #include "common.h" | 19 | #include "common.h" |
20 | 20 | ||
21 | typedef struct | ||
22 | { | ||
23 | GstElement *composition; | ||
24 | GstElement *source3; | ||
25 | } TestClosure; | ||
26 | |||
21 | static int composition_pad_added; | 27 | static int composition_pad_added; |
22 | static int composition_pad_removed; | 28 | static int composition_pad_removed; |
23 | static int seek_events; | 29 | static int seek_events; |
@@ -233,6 +239,173 @@ GST_START_TEST (test_remove_invalid_object) | |||
233 | 239 | ||
234 | GST_END_TEST; | 240 | GST_END_TEST; |
235 | 241 | ||
242 | static void | ||
243 | pad_block (GstPad * pad, gboolean blocked, gpointer user_data) | ||
244 | { | ||
245 | GstPad *ghost; | ||
246 | GstBin *bin; | ||
247 | |||
248 | if (!blocked) | ||
249 | return; | ||
250 | |||
251 | bin = GST_BIN (user_data); | ||
252 | |||
253 | ghost = gst_ghost_pad_new ("src", pad); | ||
254 | gst_pad_set_active (ghost, TRUE); | ||
255 | |||
256 | gst_element_add_pad (GST_ELEMENT (bin), ghost); | ||
257 | |||
258 | gst_pad_set_blocked_async (pad, FALSE, pad_block, NULL); | ||
259 | } | ||
260 | |||
261 | static void | ||
262 | no_more_pads_test_cb (GObject * object, TestClosure * c) | ||
263 | { | ||
264 | GstElement *source2 = GST_ELEMENT (object); | ||
265 | |||
266 | GST_WARNING ("NO MORE PADS"); | ||
267 | gst_bin_add (GST_BIN (c->composition), c->source3); | ||
268 | } | ||
269 | |||
270 | GST_START_TEST (test_no_more_pads_race) | ||
271 | { | ||
272 | GstElement *source1, *source2, *source3; | ||
273 | GstBin *bin; | ||
274 | GstElement *videotestsrc1, *videotestsrc2, *videotestsrc3; | ||
275 | GstElement *operation; | ||
276 | GstElement *composition; | ||
277 | GstElement *videomixer, *fakesink; | ||
278 | GstElement *pipeline; | ||
279 | GstBus *bus; | ||
280 | GstMessage *message; | ||
281 | GstPad *pad; | ||
282 | TestClosure closure; | ||
283 | |||
284 | /* We create a composition with an operation and three sources. The operation | ||
285 | * contains a videomixer instance and the three sources are videotestsrc's. | ||
286 | * | ||
287 | * One of the sources, source2, contains videotestsrc inside a bin. Initially | ||
288 | * the bin doesn't have a source pad. We do this to exercise the dynamic src | ||
289 | * pad code path in gnlcomposition. We block on the videotestsrc srcpad and in | ||
290 | * the pad block callback we ghost the pad and add the ghost to the parent | ||
291 | * bin. This makes gnlsource emit no-more-pads, which is used by | ||
292 | * gnlcomposition to link the source2:src pad to videomixer. | ||
293 | * | ||
294 | * We start with the composition containing operation and source1. We preroll | ||
295 | * and then add source2. Source2 will do what described above and emit | ||
296 | * no-more-pads. We connect to that no-more-pads and from there we add source3 to | ||
297 | * the composition. Adding a new source will make gnlcomposition deactivate | ||
298 | * the old stack and activate a new one. The new one contains operation, | ||
299 | * source1, source2 and source3. Source2 was active in the old stack as well and | ||
300 | * gnlcomposition is *still waiting* for no-more-pads to be emitted on it | ||
301 | * (since the no-more-pads emission is now blocked in our test's no-more-pads | ||
302 | * callback, calling gst_bin_add). In short, here, we're simulating a race between | ||
303 | * no-more-pads and someone modifying the composition. | ||
304 | * | ||
305 | * Activating the new stack, gnlcomposition calls compare_relink_single_node, | ||
306 | * which finds an existing source pad for source2 this time since we have | ||
307 | * already blocked and ghosted. It takes another code path that assumes that | ||
308 | * source2 doesn't have dynamic pads and *BOOM*. | ||
309 | */ | ||
310 | |||
311 | pipeline = GST_ELEMENT (gst_pipeline_new (NULL)); | ||
312 | bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); | ||
313 | |||
314 | composition = gst_element_factory_make ("gnlcomposition", "composition"); | ||
315 | fakesink = gst_element_factory_make ("fakesink", NULL); | ||
316 | g_object_set (fakesink, "sync", TRUE, NULL); | ||
317 | |||
318 | /* operation */ | ||
319 | operation = gst_element_factory_make ("gnloperation", "operation"); | ||
320 | videomixer = gst_element_factory_make ("videomixer", "videomixer"); | ||
321 | gst_bin_add (GST_BIN (operation), videomixer); | ||
322 | g_object_set (operation, "start", 0 * GST_SECOND, "duration", 20 * GST_SECOND, | ||
323 | "media-start", 0 * GST_SECOND, "media-duration", 20 * GST_SECOND, | ||
324 | "priority", 10, NULL); | ||
325 | gst_bin_add (GST_BIN (composition), operation); | ||
326 | |||
327 | /* source 1 */ | ||
328 | source1 = gst_element_factory_make ("gnlsource", "source1"); | ||
329 | videotestsrc1 = gst_element_factory_make ("videotestsrc", "videotestsrc1"); | ||
330 | gst_bin_add (GST_BIN (source1), videotestsrc1); | ||
331 | g_object_set (source1, "start", 0 * GST_SECOND, "duration", 10 * GST_SECOND, | ||
332 | "media-start", 0 * GST_SECOND, "media-duration", 10 * GST_SECOND, | ||
333 | "priority", 20, NULL); | ||
334 | |||
335 | /* source2 */ | ||
336 | source2 = gst_element_factory_make ("gnlsource", "source2"); | ||
337 | bin = GST_BIN (gst_bin_new (NULL)); | ||
338 | videotestsrc2 = gst_element_factory_make ("videotestsrc", "videotestsrc2"); | ||
339 | pad = gst_element_get_static_pad (videotestsrc2, "src"); | ||
340 | gst_pad_set_blocked_async (pad, TRUE, pad_block, bin); | ||
341 | gst_bin_add (bin, videotestsrc2); | ||
342 | gst_bin_add (GST_BIN (source2), GST_ELEMENT (bin)); | ||
343 | g_object_set (source2, "start", 0 * GST_SECOND, "duration", 10 * GST_SECOND, | ||
344 | "media-start", 0 * GST_SECOND, "media-duration", 10 * GST_SECOND, | ||
345 | "priority", 20, NULL); | ||
346 | |||
347 | /* source3 */ | ||
348 | source3 = gst_element_factory_make ("gnlsource", "source3"); | ||
349 | videotestsrc2 = gst_element_factory_make ("videotestsrc", "videotestsrc3"); | ||
350 | gst_bin_add (GST_BIN (source3), videotestsrc2); | ||
351 | g_object_set (source3, "start", 0 * GST_SECOND, "duration", 10 * GST_SECOND, | ||
352 | "media-start", 0 * GST_SECOND, "media-duration", 10 * GST_SECOND, | ||
353 | "priority", 20, NULL); | ||
354 | |||
355 | closure.composition = composition; | ||
356 | closure.source3 = source3; | ||
357 | g_object_connect (source2, "signal::no-more-pads", | ||
358 | no_more_pads_test_cb, &closure, NULL); | ||
359 | |||
360 | gst_bin_add (GST_BIN (composition), source1); | ||
361 | g_object_connect (composition, "signal::pad-added", | ||
362 | on_composition_pad_added_cb, fakesink, NULL); | ||
363 | g_object_connect (composition, "signal::pad-removed", | ||
364 | on_composition_pad_removed_cb, NULL, NULL); | ||
365 | |||
366 | gst_bin_add_many (GST_BIN (pipeline), composition, fakesink, NULL); | ||
367 | |||
368 | fail_if (gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PAUSED) | ||
369 | == GST_STATE_CHANGE_FAILURE); | ||
370 | |||
371 | message = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, | ||
372 | GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR); | ||
373 | if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) { | ||
374 | GError *error; | ||
375 | gchar *debug; | ||
376 | |||
377 | gst_message_parse_error (message, &error, &debug); | ||
378 | fail_if (TRUE, "error: %s - %s", error->message, debug); | ||
379 | } | ||
380 | gst_message_unref (message); | ||
381 | |||
382 | /* FIXME: maybe slow down the videotestsrc steaming thread */ | ||
383 | gst_bin_add (GST_BIN (composition), source2); | ||
384 | //g_object_set (source1, "start", 5 * GST_SECOND, NULL); | ||
385 | |||
386 | message = gst_bus_timed_pop_filtered (bus, 1 * GST_SECOND, GST_MESSAGE_ERROR); | ||
387 | if (message) { | ||
388 | if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) { | ||
389 | GError *error; | ||
390 | gchar *debug; | ||
391 | |||
392 | gst_message_parse_error (message, &error, &debug); | ||
393 | fail_if (TRUE, error->message); | ||
394 | } else { | ||
395 | fail_if (TRUE); | ||
396 | } | ||
397 | |||
398 | gst_message_unref (message); | ||
399 | } | ||
400 | |||
401 | |||
402 | gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); | ||
403 | gst_object_unref (pipeline); | ||
404 | gst_object_unref (bus); | ||
405 | } | ||
406 | |||
407 | GST_END_TEST; | ||
408 | |||
236 | Suite * | 409 | Suite * |
237 | gnonlin_suite (void) | 410 | gnonlin_suite (void) |
238 | { | 411 | { |
@@ -243,6 +416,7 @@ gnonlin_suite (void) | |||
243 | 416 | ||
244 | tcase_add_test (tc_chain, test_change_object_start_stop_in_current_stack); | 417 | tcase_add_test (tc_chain, test_change_object_start_stop_in_current_stack); |
245 | tcase_add_test (tc_chain, test_remove_invalid_object); | 418 | tcase_add_test (tc_chain, test_remove_invalid_object); |
419 | tcase_add_test (tc_chain, test_no_more_pads_race); | ||
246 | 420 | ||
247 | return s; | 421 | return s; |
248 | } | 422 | } |