From 7e85c9b0b5af5c87245285d22d2064f4ebd228cc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 10 Sep 2014 09:47:22 +0200 Subject: [PATCH] validate: Start a testsuite Currently implemented tests are: * Settup and cleanup on monitor is done properly * Some tests in the PadMonitor are done properly, namely: - Buffer before segment - Buffer outside segment - First buffer running time is always 0 - The Demuxer flow aggregation is properly checked https://bugzilla.gnome.org/show_bug.cgi?id=736379 --- validate/Makefile.am | 1 + validate/configure.ac | 3 + validate/gst/validate/validate.h | 5 + validate/tests/Makefile.am | 10 + validate/tests/check/Makefile.am | 96 ++++++ validate/tests/check/validate/monitoring.c | 110 ++++++ validate/tests/check/validate/padmonitor.c | 382 +++++++++++++++++++++ validate/tests/check/validate/test-utils.c | 198 +++++++++++ validate/tests/check/validate/test-utils.h | 58 ++++ 9 files changed, 863 insertions(+) create mode 100644 validate/tests/Makefile.am create mode 100644 validate/tests/check/Makefile.am create mode 100644 validate/tests/check/validate/monitoring.c create mode 100644 validate/tests/check/validate/padmonitor.c create mode 100644 validate/tests/check/validate/test-utils.c create mode 100644 validate/tests/check/validate/test-utils.h diff --git a/validate/Makefile.am b/validate/Makefile.am index 514c383ffa..48dc766106 100644 --- a/validate/Makefile.am +++ b/validate/Makefile.am @@ -7,6 +7,7 @@ SUBDIRS = \ tools \ pkgconfig \ docs \ + tests \ po DIST_SUBDIRS = $(SUBDIRS) diff --git a/validate/configure.ac b/validate/configure.ac index b604fa45f8..7b9e22a92a 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -179,6 +179,7 @@ AC_SUBST(GIO_LIBS) dnl checks for gstreamer AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) +AM_CONDITIONAL(HAVE_GST_CHECK, test "x$HAVE_GST_CHECK" = "xyes") dnl *** set variables based on configure arguments *** @@ -278,6 +279,8 @@ gst/Makefile gst/validate/Makefile gst/preload/Makefile gst/overrides/Makefile +tests/Makefile +tests/check/Makefile pkgconfig/Makefile pkgconfig/gst-validate-uninstalled.pc pkgconfig/gst-validate.pc diff --git a/validate/gst/validate/validate.h b/validate/gst/validate/validate.h index e97cadba1d..1aaec67241 100644 --- a/validate/gst/validate/validate.h +++ b/validate/gst/validate/validate.h @@ -2,6 +2,9 @@ * Copyright (C) 2013 Thiago Santos */ +#ifndef _GST_VALIDATE_H +#define _GST_VALIDATE_H + #include #include #include @@ -10,3 +13,5 @@ #include void gst_validate_init (void); + +#endif /* _GST_VALIDATE_H */ diff --git a/validate/tests/Makefile.am b/validate/tests/Makefile.am new file mode 100644 index 0000000000..8bbfc8facd --- /dev/null +++ b/validate/tests/Makefile.am @@ -0,0 +1,10 @@ +if HAVE_GST_CHECK +CHECK_SUBDIRS= check +else +CHECK_SUBDIRS= +endif + +SUBDIRS= $(CHECK_SUBDIRS) + +DIST_SUBDIRS = check + diff --git a/validate/tests/check/Makefile.am b/validate/tests/check/Makefile.am new file mode 100644 index 0000000000..8bde59f4b8 --- /dev/null +++ b/validate/tests/check/Makefile.am @@ -0,0 +1,96 @@ +include $(top_srcdir)/common/check.mak + +TESTS_ENVIRONMENT = + +plugindir = $(libdir)/gstreamer-@GST_API_VERSION@ + +# override to _not_ install the test plugins +install-pluginLTLIBRARIES: + +# the core dumps of some machines have PIDs appended +CLEANFILES = core.* test-registry.* *.gcno *.gcda + +common_cflags=-I$(top_srcdir) $(GST_PLUGINS_BASE_CFLAGS) $(GST_OBJ_CFLAGS) \ + $(GST_CHECK_CFLAGS) $(GST_OPTION_CFLAGS) $(GST_CFLAGS) +common_ldadd=$(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la \ + $(GST_PLUGINS_BASE_LIBS) -lgstpbutils-$(GST_API_VERSION) \ + $(GST_OBJ_LIBS) $(GST_CHECK_LIBS) + +testutils_noisnt_libraries=libtestutils.la +testutils_noinst_headers=validate/test-utils.h +libtestutils_la_LIBADD=$(common_ldadd) +libtestutils_la_CFLAGS=$(common_cflags) +libtestutils_la_SOURCES=validate/test-utils.c + +SUPPRESSIONS = $(top_srcdir)/common/gst.supp # $(srcdir)/gst-plugins-bad.supp + +clean-local: clean-local-check + +check_PROGRAMS = \ + validate/padmonitor \ + validate/monitoring + +noinst_LTLIBRARIES=$(testutils_noisnt_libraries) +noinst_HEADERS=$(testutils_noinst_headers) + +TESTS = $(check_PROGRAMS) + +AM_CFLAGS = $(common_cflags) -UG_DISABLE_ASSERT -UG_DISABLE_CAST_CHECKS +LDADD = $(common_ldadd) libtestutils.la + +debug: + echo $(COVERAGE_FILES) + echo $(COVERAGE_FILES_REL) + +.PHONY: coverage +if GST_GCOV_ENABLED +# we rebuild a registry and do gst-inspect so that all the get/set codepaths +# are also covered +coverage: + make check + make coverage-report +else +coverage: + echo "You need to configure with --enable-gcov to get coverage data" + exit 1 +endif + +coverage-report: + if test ! -e coverage; then + rm -r coverage + fi + for dir in $(COVERAGE_DIRS); do \ + mkdir -p coverage/$$dir; \ + make -C $(top_builddir)/$$dir gcov; \ + done + for dir in $(COVERAGE_DIRS); do \ + files="`ls $(top_builddir)/$$dir/*.gcov.out 2> /dev/null`"; \ + if test ! -z "$$files"; then \ + perl $(top_srcdir)/common/coverage/coverage-report.pl \ + $(top_builddir)/$$dir/*.gcov.out > \ + coverage/$$dir/index.xml; \ + xsltproc $(top_srcdir)/common/coverage/coverage-report.xsl \ + coverage/$$dir/index.xml > coverage/$$dir/index.html; \ + fi; \ + done + for file in $(COVERAGE_FILES_REL); do \ + echo Generating coverage/$$file.html; \ + perl $(top_srcdir)/common/coverage/coverage-report-entry.pl \ + $(top_builddir)/$$file > coverage/$$file.html; \ + done + +check-integration: integration + CK_DEFAULT_TIMEOUT=20 ./integration + +check-integration-forever: + @while true; do \ + make check-integration \ + CK_DEFAULT_TIMEOUT=20 \ + $* || break; done + +check-integration-gdb: + @$(TESTS_ENVIRONMENT) \ + CK_FORK=no \ + $(LIBTOOL) --mode=execute \ + gdb ./integration + diff --git a/validate/tests/check/validate/monitoring.c b/validate/tests/check/validate/monitoring.c new file mode 100644 index 0000000000..7ad2ed2e42 --- /dev/null +++ b/validate/tests/check/validate/monitoring.c @@ -0,0 +1,110 @@ +/* GstValidate + * Copyright (C) 2014 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include "test-utils.h" + +GST_START_TEST (monitors_added) +{ + GList *tmp; + GstValidateRunner *runner; + GstValidateMonitor *monitor; + GstElement *pipeline = gst_pipeline_new ("validate-pipeline"); + GstElement *src, *sink; + + src = gst_element_factory_make ("fakesrc", "source"); + sink = gst_element_factory_make ("fakesink", "sink"); + + runner = gst_validate_runner_new (); + fail_unless (GST_IS_VALIDATE_RUNNER (runner)); + + monitor = gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), + runner, NULL); + fail_unless (GST_IS_VALIDATE_BIN_MONITOR (monitor)); + + gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL); + gst_element_link (src, sink); + + /* Check that the elements are properly monitored */ + fail_unless_equals_int (g_list_length (src->srcpads), 1); + for (tmp = src->srcpads; tmp; tmp = tmp->next) + fail_unless (GST_IS_VALIDATE_PAD_MONITOR (g_object_get_data ((GObject *) + tmp->data, "validate-monitor"))); + + fail_unless_equals_int (g_list_length (sink->sinkpads), 1); + for (tmp = sink->sinkpads; tmp; tmp = tmp->next) + fail_unless (GST_IS_VALIDATE_PAD_MONITOR (g_object_get_data ((GObject *) + tmp->data, "validate-monitor"))); + + /* clean up */ + gst_object_unref (pipeline); + gst_object_unref (monitor); + gst_object_unref (runner); +} + +GST_END_TEST; + +GST_START_TEST (monitors_cleanup) +{ + GstElement *src, *sink; + GstValidateRunner *runner; + GstValidateMonitor *monitor, *pmonitor1, *pmonitor2; + + GstElement *pipeline = gst_pipeline_new ("validate-pipeline"); + + src = gst_element_factory_make ("fakesrc", "source"); + sink = gst_element_factory_make ("fakesink", "sink"); + + runner = gst_validate_runner_new (); + monitor = gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), + runner, NULL); + gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL); + gst_element_link (src, sink); + + /* Check cleanup */ + pmonitor1 = + g_object_get_data ((GObject *) src->srcpads->data, "validate-monitor"); + pmonitor2 = + g_object_get_data ((GObject *) sink->sinkpads->data, "validate-monitor"); + check_destroyed (monitor, pmonitor1, pmonitor2, NULL); + check_destroyed (pipeline, src, sink, NULL); +} + +GST_END_TEST; + + +static Suite * +gst_validate_suite (void) +{ + Suite *s = suite_create ("monitoring"); + TCase *tc_chain = tcase_create ("monitoring"); + suite_add_tcase (s, tc_chain); + + gst_validate_init (); + + tcase_add_test (tc_chain, monitors_added); + tcase_add_test (tc_chain, monitors_cleanup); + + return s; +} + +GST_CHECK_MAIN (gst_validate); diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c new file mode 100644 index 0000000000..4876cd4f1d --- /dev/null +++ b/validate/tests/check/validate/padmonitor.c @@ -0,0 +1,382 @@ +/* GstValidate + * Copyright (C) 2014 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include "test-utils.h" + +GST_START_TEST (buffer_before_segment) +{ + GstPad *srcpad; + GstElement *src, *sink; + GstValidateRunner *runner; + GstValidateReport *report; + GstValidateMonitor *monitor; + + /* getting an existing element class is cheating, but easier */ + src = gst_element_factory_make ("fakesrc", "fakesrc"); + sink = gst_element_factory_make ("fakesink", "fakesink"); + + fail_unless (gst_element_link (src, sink)); + + runner = gst_validate_runner_new (); + monitor = + gst_validate_monitor_factory_create (GST_OBJECT (src), runner, NULL); + gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); + fail_unless (GST_IS_VALIDATE_ELEMENT_MONITOR (monitor)); + + srcpad = gst_element_get_static_pad (src, "src"); + + /* We want to handle the src behaviour ourself */ + fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE)); + fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_PLAYING), + GST_STATE_CHANGE_ASYNC); + + /* Send a buffer before pushing any segment (FAILS) */ + { + _gst_check_expecting_log = TRUE; + fail_unless_equals_int (gst_pad_push (srcpad, gst_buffer_new ()), + GST_FLOW_OK); + + assert_equals_int (g_slist_length (runner->reports), 1); + report = runner->reports->data; + fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_WARNING); + fail_unless_equals_int (report->issue->issue_id, + GST_VALIDATE_ISSUE_ID_BUFFER_BEFORE_SEGMENT); + } + + /* Setup all needed event and push a new buffer (WORKS) */ + { + _gst_check_expecting_log = FALSE; + gst_check_setup_events (srcpad, src, NULL, GST_FORMAT_TIME); + fail_unless_equals_int (gst_pad_push (srcpad, gst_buffer_new ()), + GST_FLOW_OK); + assert_equals_int (g_slist_length (runner->reports), 1); + } + + /* clean up */ + fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, FALSE)); + fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_NULL), + GST_STATE_CHANGE_SUCCESS); + + gst_object_unref (srcpad); + check_destroyed (src, srcpad, NULL); + check_destroyed (sink, NULL, NULL); + check_destroyed (runner, NULL, NULL); +} + +GST_END_TEST; + +GST_START_TEST (buffer_outside_segment) +{ + GstPad *srcpad; + GstBuffer *buffer; + GstSegment segment; + GstElement *src, *sink; + const gchar *fakesrc_klass; + GstValidateReport *report; + GstValidateRunner *runner; + GstValidateMonitor *monitor; + + /* getting an existing element class is cheating, but easier */ + src = gst_element_factory_make ("fakesrc", "fakesrc"); + sink = gst_element_factory_make ("fakesink", "fakesink"); + + fakesrc_klass = + gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (src), "klass"); + + /* Testing if a buffer is outside a segment is only done for buffer outputed + * from decoders for the moment, fake a Decoder so that the test is properly + * executed */ + gst_element_class_add_metadata (GST_ELEMENT_GET_CLASS (src), "klass", + "Decoder"); + + runner = gst_validate_runner_new (); + monitor = + gst_validate_monitor_factory_create (GST_OBJECT (src), runner, NULL); + gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); + + srcpad = gst_element_get_static_pad (src, "src"); + fail_unless (GST_IS_VALIDATE_PAD_MONITOR (g_object_get_data ((GObject *) + srcpad, "validate-monitor"))); + + fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE)); + fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_PLAYING), + GST_STATE_CHANGE_ASYNC); + + gst_segment_init (&segment, GST_FORMAT_TIME); + segment.start = 0; + segment.stop = GST_SECOND; + fail_unless (gst_pad_push_event (srcpad, + gst_event_new_stream_start ("the-stream"))); + fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&segment))); + + + /* Pushing a buffer that is outside the segment */ + { + buffer = gst_buffer_new (); + GST_BUFFER_PTS (buffer) = 10 * GST_SECOND; + GST_BUFFER_DURATION (buffer) = GST_SECOND; + fail_unless (gst_pad_push (srcpad, buffer)); + + assert_equals_int (g_slist_length (runner->reports), 1); + report = runner->reports->data; + fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_ISSUE); + fail_unless_equals_int (report->issue->issue_id, + GST_VALIDATE_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT); + } + + /* Pushing a buffer inside the segment */ + { + fail_unless (gst_pad_push (srcpad, gst_buffer_new ())); + assert_equals_int (g_slist_length (runner->reports), 1); + } + + + /* clean up */ + fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, FALSE)); + gst_object_unref (srcpad); + + gst_element_class_add_metadata (GST_ELEMENT_GET_CLASS (src), "klass", + fakesrc_klass); + gst_object_unref (src); + gst_object_unref (runner); + + fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_NULL), + GST_STATE_CHANGE_SUCCESS); + gst_object_unref (sink); +} + +GST_END_TEST; + +static void +_first_buffer_running_time (gboolean failing) +{ + GstPad *srcpad; + GstBuffer *buffer; + GstElement *src, *sink; + GstValidateReport *report; + GstValidateRunner *runner; + GstValidateMonitor *monitor; + + /* getting an existing element class is cheating, but easier */ + src = gst_element_factory_make ("fakesrc", "fakesrc"); + sink = gst_element_factory_make ("fakesink", "fakesink"); + + runner = gst_validate_runner_new (); + monitor = + gst_validate_monitor_factory_create (GST_OBJECT (src), runner, NULL); + gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); + + srcpad = gst_element_get_static_pad (src, "src"); + fail_unless (GST_IS_VALIDATE_PAD_MONITOR (g_object_get_data ((GObject *) + srcpad, "validate-monitor"))); + + fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE)); + fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_PLAYING), + GST_STATE_CHANGE_ASYNC); + + gst_check_setup_events (srcpad, src, NULL, GST_FORMAT_TIME); + + /* Pushing a first buffer that as a wrong running time */ + { + buffer = gst_buffer_new (); + + if (failing) + GST_BUFFER_PTS (buffer) = 23; + + GST_BUFFER_DURATION (buffer) = GST_SECOND; + fail_unless (gst_pad_push (srcpad, buffer)); + + if (failing) { + assert_equals_int (g_slist_length (runner->reports), 1); + report = runner->reports->data; + fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_WARNING); + fail_unless_equals_int (report->issue->issue_id, + GST_VALIDATE_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO); + } else { + assert_equals_int (g_slist_length (runner->reports), 0); + } + } + + /* clean up */ + fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, FALSE)); + fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_NULL), + GST_STATE_CHANGE_SUCCESS); + + gst_object_unref (srcpad); + check_destroyed (src, srcpad, NULL); + check_destroyed (sink, NULL, NULL); + check_destroyed (runner, NULL, NULL); + check_destroyed (monitor, NULL, NULL); +} + +GST_START_TEST (first_buffer_running_time) +{ + /* First run the test with a first buffer timestamp != 0 */ + _first_buffer_running_time (TRUE); + + /* First run the test with a first buffer timestamp == 0 */ + _first_buffer_running_time (FALSE); +} + +GST_END_TEST; + +static void +fake_demuxer_prepare_pads (GstBin * pipeline, GstElement * demux, + GstValidateRunner * runner) +{ + gint i = 0; + GList *tmp; + + fail_unless (g_list_length (demux->srcpads), 3); + + for (tmp = demux->srcpads; tmp; tmp = tmp->next) { + GstPad *new_peer; + gchar *name = g_strdup_printf ("sink-%d", i++); + GstElement *sink = gst_element_factory_make ("fakesink", name); + + gst_bin_add (pipeline, sink); + + new_peer = sink->sinkpads->data; + gst_pad_link (tmp->data, new_peer); + gst_element_set_state (sink, GST_STATE_PLAYING); + gst_pad_activate_mode (tmp->data, GST_PAD_MODE_PUSH, TRUE); + + g_free (name); + } + + fail_unless (gst_pad_activate_mode (demux->sinkpads->data, GST_PAD_MODE_PUSH, + TRUE)); +} + +static GstValidatePadMonitor * +_get_pad_monitor (GstPad * pad) +{ + GstValidatePadMonitor *m = get_pad_monitor (pad); + + gst_object_unref (pad); + + return m; +} + +static void +_test_flow_aggregation (GstFlowReturn flow, GstFlowReturn flow1, + GstFlowReturn flow2, GstFlowReturn demux_flow, gboolean should_fail) +{ + GstPad *srcpad; + GstValidateReport *report; + GstValidatePadMonitor *pmonitor, *pmonitor1, *pmonitor2; + GstElement *demuxer = fake_demuxer_new (); + GstBin *pipeline = GST_BIN (gst_pipeline_new ("validate-pipeline")); + + GstValidateRunner *runner = gst_validate_runner_new (); + GstValidateMonitor *monitor = + gst_validate_monitor_factory_create (GST_OBJECT (pipeline), + runner, NULL); + gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); + + + gst_bin_add (pipeline, demuxer); + fake_demuxer_prepare_pads (pipeline, demuxer, runner); + + srcpad = gst_pad_new ("srcpad1", GST_PAD_SRC); + gst_pad_link (srcpad, demuxer->sinkpads->data); + fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE)); + gst_check_setup_events_with_stream_id (srcpad, demuxer, NULL, + GST_FORMAT_TIME, "the-stream"); + + pmonitor = _get_pad_monitor (gst_pad_get_peer (demuxer->srcpads->data)); + pmonitor1 = + _get_pad_monitor (gst_pad_get_peer (demuxer->srcpads->next->data)); + pmonitor2 = + _get_pad_monitor (gst_pad_get_peer (demuxer->srcpads->next->next->data)); + + pmonitor->last_flow_return = flow; + pmonitor1->last_flow_return = flow1; + pmonitor2->last_flow_return = flow2; + FAKE_DEMUXER (demuxer)->return_value = demux_flow; + + fail_unless_equals_int (gst_pad_push (srcpad, gst_buffer_new ()), demux_flow); + + if (should_fail) { + assert_equals_int (g_slist_length (runner->reports), 1); + report = runner->reports->data; + fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_CRITICAL); + fail_unless_equals_int (report->issue->issue_id, + GST_VALIDATE_ISSUE_ID_WRONG_FLOW_RETURN); + } else { + assert_equals_int (g_slist_length (runner->reports), 0); + + } + + clean_bus (GST_ELEMENT (pipeline)); + + gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); + ASSERT_OBJECT_REFCOUNT (pipeline, "ours", 1); + check_destroyed (pipeline, demuxer, NULL); + check_destroyed (monitor, pmonitor, NULL); +} + +GST_START_TEST (flow_aggregation) +{ + /* Check the GstFlowCombiner to find the rules */ + + /* Failling cases: */ + _test_flow_aggregation (GST_FLOW_OK, GST_FLOW_OK, + GST_FLOW_ERROR, GST_FLOW_OK, TRUE); + _test_flow_aggregation (GST_FLOW_EOS, GST_FLOW_EOS, + GST_FLOW_EOS, GST_FLOW_OK, TRUE); + _test_flow_aggregation (GST_FLOW_FLUSHING, GST_FLOW_OK, + GST_FLOW_OK, GST_FLOW_OK, TRUE); + _test_flow_aggregation (GST_FLOW_NOT_NEGOTIATED, GST_FLOW_OK, + GST_FLOW_OK, GST_FLOW_OK, TRUE); + + /* Passing cases: */ + _test_flow_aggregation (GST_FLOW_EOS, GST_FLOW_EOS, + GST_FLOW_EOS, GST_FLOW_EOS, FALSE); + _test_flow_aggregation (GST_FLOW_EOS, GST_FLOW_EOS, + GST_FLOW_OK, GST_FLOW_OK, FALSE); + _test_flow_aggregation (GST_FLOW_OK, GST_FLOW_OK, + GST_FLOW_OK, GST_FLOW_EOS, FALSE); + _test_flow_aggregation (GST_FLOW_NOT_NEGOTIATED, GST_FLOW_OK, + GST_FLOW_OK, GST_FLOW_NOT_NEGOTIATED, FALSE); +} + +GST_END_TEST; + +static Suite * +gst_validate_suite (void) +{ + Suite *s = suite_create ("padmonitor"); + TCase *tc_chain = tcase_create ("padmonitor"); + suite_add_tcase (s, tc_chain); + + gst_validate_init (); + + tcase_add_test (tc_chain, buffer_before_segment); + tcase_add_test (tc_chain, buffer_outside_segment); + tcase_add_test (tc_chain, first_buffer_running_time); + tcase_add_test (tc_chain, flow_aggregation); + + return s; +} + +GST_CHECK_MAIN (gst_validate); diff --git a/validate/tests/check/validate/test-utils.c b/validate/tests/check/validate/test-utils.c new file mode 100644 index 0000000000..51b8fd014f --- /dev/null +++ b/validate/tests/check/validate/test-utils.c @@ -0,0 +1,198 @@ +/* GstValidate + * Copyright (C) 2014 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "test-utils.h" + +typedef struct _DestroyedObjectStruct +{ + GObject *object; + gboolean destroyed; +} DestroyedObjectStruct; + +static void +weak_notify (DestroyedObjectStruct * destroyed, GObject ** object) +{ + destroyed->destroyed = TRUE; +} + +void +check_destroyed (gpointer object_to_unref, gpointer first_object, ...) +{ + gint i = 0; + GObject *object; + GList *objs = NULL, *tmp; + DestroyedObjectStruct *destroyed = g_slice_new0 (DestroyedObjectStruct); + + destroyed->object = G_OBJECT (object_to_unref); + g_object_weak_ref (G_OBJECT (object_to_unref), (GWeakNotify) weak_notify, + destroyed); + objs = g_list_prepend (objs, destroyed); + + if (first_object) { + va_list varargs; + + object = G_OBJECT (first_object); + + va_start (varargs, first_object); + while (object) { + destroyed = g_slice_new0 (DestroyedObjectStruct); + destroyed->object = object; + g_object_weak_ref (object, (GWeakNotify) weak_notify, destroyed); + objs = g_list_append (objs, destroyed); + object = va_arg (varargs, GObject *); + } + va_end (varargs); + } + gst_object_unref (object_to_unref); + + for (tmp = objs; tmp; tmp = tmp->next) { + fail_unless (((DestroyedObjectStruct *) tmp->data)->destroyed == TRUE, + "%p is not destroyed (object nb %i)", + ((DestroyedObjectStruct *) tmp->data)->object, i); + g_slice_free (DestroyedObjectStruct, tmp->data); + i++; + } + g_list_free (objs); + +} + +void +clean_bus (GstElement * element) +{ + GstBus *bus; + + bus = gst_element_get_bus (element); + gst_bus_set_flushing (bus, TRUE); + gst_object_unref (bus); +} + +GstValidatePadMonitor * +get_pad_monitor (GstPad * pad) +{ + return g_object_get_data ((GObject *) pad, "validate-monitor"); +} + +static GstStaticPadTemplate fake_demuxer_src_template = +GST_STATIC_PAD_TEMPLATE ("src%u", + GST_PAD_SRC, + GST_PAD_SOMETIMES, + GST_STATIC_CAPS ("something") + ); + +static GstStaticPadTemplate fake_demuxer_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("something") + ); + +static void +fake_demuxer_dispose (FakeDemuxer * self) +{ +} + +static void +fake_demuxer_finalize (FakeDemuxer * self) +{ +} + +static GstFlowReturn +_chain (GstPad * pad, GstObject * self, GstBuffer * buffer) +{ + gst_buffer_unref (buffer); + + return FAKE_DEMUXER (self)->return_value; +} + +static void +fake_demuxer_init (FakeDemuxer * self, gpointer * g_class) +{ + GstPad *pad; + GstElement *element = GST_ELEMENT (self); + GstPadTemplate *pad_template; + + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src%u"); + + pad = gst_pad_new_from_template (pad_template, "src0"); + gst_element_add_pad (element, pad); + + pad = gst_pad_new_from_template (pad_template, "src1"); + gst_element_add_pad (element, pad); + + pad = gst_pad_new_from_template (pad_template, "src2"); + gst_element_add_pad (element, pad); + + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink"); + pad = gst_pad_new_from_template (pad_template, "sink"); + gst_element_add_pad (element, pad); + + self->return_value = GST_FLOW_OK; + + gst_pad_set_chain_function (pad, _chain); +} + +static void +fake_demuxer_class_init (FakeDemuxerClass * self_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (self_class); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (self_class); + + object_class->dispose = (void (*)(GObject * object)) fake_demuxer_dispose; + object_class->finalize = (void (*)(GObject * object)) fake_demuxer_finalize; + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&fake_demuxer_src_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&fake_demuxer_sink_template)); + gst_element_class_set_static_metadata (gstelement_class, + "Fake Demuxer", "Demuxer", "Some demuxer", "Thibault Saunier"); +} + +GType +fake_demuxer_get_type (void) +{ + static volatile gsize type = 0; + + if (g_once_init_enter (&type)) { + GType _type; + static const GTypeInfo info = { + sizeof (FakeDemuxerClass), + NULL, + NULL, + (GClassInitFunc) fake_demuxer_class_init, + NULL, + NULL, + sizeof (FakeDemuxer), + 0, + (GInstanceInitFunc) fake_demuxer_init, + }; + + _type = g_type_register_static (GST_TYPE_ELEMENT, "FakeDemuxer", &info, 0); + g_once_init_leave (&type, _type); + } + return type; +} + +GstElement * +fake_demuxer_new (void) +{ + return GST_ELEMENT (g_object_new (FAKE_DEMUXER_TYPE, NULL)); +} diff --git a/validate/tests/check/validate/test-utils.h b/validate/tests/check/validate/test-utils.h new file mode 100644 index 0000000000..a8dfd0ebb4 --- /dev/null +++ b/validate/tests/check/validate/test-utils.h @@ -0,0 +1,58 @@ +/* GstValidate + * Copyright (C) 2014 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GST_VALIDATE_TEST_UTILS +#define _GST_VALIDATE_TEST_UTILS + +#include "test-utils.h" +#include +#include +#include + +G_BEGIN_DECLS + +void check_destroyed (gpointer object_to_unref, gpointer first_object, ...) G_GNUC_NULL_TERMINATED; +GstValidateRunner * setup_runner (GstObject * object); +void clean_bus (GstElement *element); +GstValidatePadMonitor * get_pad_monitor (GstPad *pad); + +typedef struct { + GstElement parent; + + GstFlowReturn return_value; +} FakeDemuxer; + +typedef struct { + GstElementClass parent; +} FakeDemuxerClass; + +#define FAKE_DEMUXER_TYPE (fake_demuxer_get_type ()) +#define FAKE_DEMUXER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FAKE_DEMUXER_TYPE, FakeDemuxer)) +#define FAKE_DEMUXER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), FAKE_DEMUXER_TYPE, FakeDemuxerClass)) +#define IS_FAKE_DEMUXER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FAKE_DEMUXER_TYPE)) +#define IS_FAKE_DEMUXER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FAKE_DEMUXER_TYPE)) +#define FAKE_DEMUXER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), FAKE_DEMUXER_TYPE, FakeDemuxerClass)) + +GType fake_demuxer_get_type (void); +GstElement * fake_demuxer_new (void); + + +G_END_DECLS + +#endif /* _GST_VALIDATE_TEST_UTILS */