summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlessandro Decina <alessandro.decina@collabora.co.uk>2010-08-12 15:53:42 +0200
committerAlessandro Decina <alessandro.decina@collabora.co.uk>2010-08-20 10:31:38 +0200
commit32fa1002d03f6e291265c04bcd3bf82f5101671c (patch)
tree86abd2b3ef4106d93b9d36509e71ca96dd085ebc
parent00b4bfa48f23e671b40c36e428ebfc224f0e3c9c (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.c174
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
21typedef struct
22{
23 GstElement *composition;
24 GstElement *source3;
25} TestClosure;
26
21static int composition_pad_added; 27static int composition_pad_added;
22static int composition_pad_removed; 28static int composition_pad_removed;
23static int seek_events; 29static int seek_events;
@@ -233,6 +239,173 @@ GST_START_TEST (test_remove_invalid_object)
233 239
234GST_END_TEST; 240GST_END_TEST;
235 241
242static void
243pad_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
261static void
262no_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
270GST_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
407GST_END_TEST;
408
236Suite * 409Suite *
237gnonlin_suite (void) 410gnonlin_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}