summaryrefslogtreecommitdiff
path: root/tests/check/elements/curlhttpsrc.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/check/elements/curlhttpsrc.c')
-rw-r--r--tests/check/elements/curlhttpsrc.c693
1 files changed, 693 insertions, 0 deletions
diff --git a/tests/check/elements/curlhttpsrc.c b/tests/check/elements/curlhttpsrc.c
new file mode 100644
index 000000000..fa6288f01
--- /dev/null
+++ b/tests/check/elements/curlhttpsrc.c
@@ -0,0 +1,693 @@
+/* GStreamer unit tests for the curlhttpsrc element
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include <gio/gio.h>
+#include <glib.h>
+#include <glib/gprintf.h>
+
+#include <gst/check/gstcheck.h>
+
+gboolean redirect = TRUE;
+
+static const char **cookies = NULL;
+
+typedef struct _GioHttpServer
+{
+ guint16 port;
+ char *root;
+ GSocketService *service;
+ guint64 delay;
+} GioHttpServer;
+
+typedef struct _HttpRequest
+{
+ gchar *method;
+ gchar *version;
+ gchar *path;
+ gchar *query;
+} HttpRequest;
+
+static GioHttpServer *run_server (void);
+static void stop_server (GioHttpServer * server);
+static guint16 get_port_from_server (GioHttpServer * server);
+
+static const gchar *STATUS_OK = "200 OK";
+static const gchar *STATUS_MOVED_PERMANENTLY = "301 Moved Permanently";
+static const gchar *STATUS_MOVED_TEMPORARILY = "302 Moved Temporarily";
+static const gchar *STATUS_TEMPORARY_REDIRECT = "307 Temporary Redirect";
+static const gchar *STATUS_FORBIDDEN = "403 Forbidden";
+static const gchar *STATUS_NOT_FOUND = "404 Not Found";
+
+static void
+do_get (GioHttpServer * server, const HttpRequest * req, GOutputStream * out)
+{
+ gboolean send_error_doc = FALSE;
+ int buflen = 1024;
+ const gchar *status = STATUS_OK;
+ const gchar *content_type = "application/octet-stream";
+ GString *s;
+ char *buf = NULL;
+ gsize written = 0;
+
+ GST_DEBUG ("%s request: \"%s\"", req->method, req->path);
+
+ if (!strcmp (req->path, "/301"))
+ status = STATUS_MOVED_PERMANENTLY;
+ else if (!strcmp (req->path, "/302"))
+ status = STATUS_MOVED_TEMPORARILY;
+ else if (!strcmp (req->path, "/307"))
+ status = STATUS_TEMPORARY_REDIRECT;
+ else if (!strcmp (req->path, "/403"))
+ status = STATUS_FORBIDDEN;
+ else if (!strcmp (req->path, "/404"))
+ status = STATUS_NOT_FOUND;
+ else if (!strcmp (req->path, "/404-with-data")) {
+ status = STATUS_NOT_FOUND;
+ send_error_doc = TRUE;
+ }
+ s = g_string_new ("HTTP/");
+ g_string_append_printf (s, "%s %s\r\n", req->version, status);
+
+ if (g_str_has_prefix (status, "30")) {
+ g_string_append_printf (s, "Location: %s-redirected\r\n", req->path);
+ }
+
+ if (status == STATUS_OK || send_error_doc) {
+ g_string_append_printf (s, "Content-Type: %s\r\n", content_type);
+ g_string_append_printf (s, "Content-Length: %lu\r\n", (gulong) buflen);
+ if (!g_strcmp0 (req->method, "GET")) {
+ buf = g_malloc (buflen);
+ memset (buf, 0, buflen);
+ }
+ }
+
+ g_string_append (s, "\r\n");
+ GST_DEBUG ("Response headers: %lu\n%s\n********\n", s->len, s->str);
+ g_output_stream_write_all (out, s->str, s->len, &written, NULL, NULL);
+ fail_if (written != s->len);
+ g_string_free (s, TRUE);
+ if (buf) {
+ g_output_stream_write_all (out, buf, buflen, &written, NULL, NULL);
+ fail_if (written != buflen);
+ g_free (buf);
+ }
+}
+
+static void
+send_error (GOutputStream * out, int error_code, const gchar * reason)
+{
+ gchar *res;
+
+ res = g_strdup_printf ("HTTP/1.0 %d %s\r\n\r\n"
+ "<html><head><title>%d %s</title></head>"
+ "<body>%s</body></html>", error_code, reason, error_code, reason, reason);
+ g_output_stream_write_all (out, res, strlen (res), NULL, NULL, NULL);
+ g_free (res);
+}
+
+static gboolean
+server_callback (GThreadedSocketService * service,
+ GSocketConnection * connection,
+ GSocketListener * listener, gpointer user_data)
+{
+ GioHttpServer *server = (GioHttpServer *) user_data;
+ GOutputStream *out;
+ GInputStream *in;
+ GDataInputStream *data = NULL;
+ char *line = NULL, *escaped, *tmp;
+ HttpRequest req;
+
+ in = g_io_stream_get_input_stream (G_IO_STREAM (connection));
+ out = g_io_stream_get_output_stream (G_IO_STREAM (connection));
+
+ data = g_data_input_stream_new (in);
+
+ g_data_input_stream_set_newline_type (data, G_DATA_STREAM_NEWLINE_TYPE_ANY);
+
+ line = g_data_input_stream_read_line (data, NULL, NULL, NULL);
+
+ if (line == NULL) {
+ send_error (out, 400, "Invalid request");
+ goto out;
+ }
+
+ tmp = strchr (line, ' ');
+ if (!tmp) {
+ send_error (out, 400, "Invalid request");
+ goto out;
+ }
+ req.method = line;
+ *tmp = '\0';
+ escaped = tmp + 1;
+
+ req.version = NULL;
+ tmp = strchr (escaped, ' ');
+ if (tmp != NULL) {
+ *tmp = 0;
+ req.version = tmp + 6; /* skip "HTTP/" from version field */
+ }
+
+ req.query = strchr (escaped, '?');
+ if (req.query != NULL) {
+ *req.query = '\0';
+ req.query++;
+ }
+
+ req.path = g_uri_unescape_string (escaped, NULL);
+
+ GST_DEBUG ("%s %s HTTP/%s", req.method, req.path, req.version);
+
+ if (server->delay) {
+ g_usleep (server->delay);
+ }
+ do_get (server, &req, out);
+
+ g_free (req.path);
+out:
+ g_free (line);
+ if (data)
+ g_object_unref (data);
+
+ return TRUE;
+}
+
+static guint16
+get_port_from_server (GioHttpServer * server)
+{
+ fail_if (server == NULL);
+ return server->port;
+}
+
+static GioHttpServer *
+run_server (void)
+{
+ GioHttpServer *server;
+ GError *error = NULL;
+
+ server = g_slice_new0 (GioHttpServer);
+ server->service = g_threaded_socket_service_new (10);
+ server->port =
+ g_socket_listener_add_any_inet_port (G_SOCKET_LISTENER (server->service),
+ NULL, &error);
+ fail_if (server->port == 0);
+ g_signal_connect (server->service, "run", G_CALLBACK (server_callback),
+ server);
+
+ GST_DEBUG ("HTTP server listening on port %u", server->port);
+
+ /* check if we can connect to our local http server */
+ {
+ GSocketConnection *conn;
+ GSocketClient *client;
+
+ client = g_socket_client_new ();
+ g_socket_client_set_timeout (client, 2);
+ conn =
+ g_socket_client_connect_to_host (client, "127.0.0.1", server->port,
+ NULL, NULL);
+ if (conn == NULL) {
+ GST_INFO ("Couldn't connect to 127.0.0.1:%u", server->port);
+ g_object_unref (client);
+ g_slice_free (GioHttpServer, server);
+ return NULL;
+ }
+
+ g_object_unref (conn);
+ g_object_unref (client);
+ }
+
+ return server;
+}
+
+static void
+stop_server (GioHttpServer * server)
+{
+ fail_if (server == NULL);
+ GST_DEBUG ("Stopping server...");
+ g_socket_service_stop (server->service);
+ g_socket_listener_close (G_SOCKET_LISTENER (server->service));
+ g_object_unref (server->service);
+ g_slice_free (GioHttpServer, server);
+ GST_DEBUG ("Server stopped");
+}
+
+static void
+handoff_cb (GstElement * fakesink, GstBuffer * buf, GstPad * pad,
+ GstBuffer ** p_outbuf)
+{
+ GST_LOG ("handoff, buf = %p", buf);
+ if (*p_outbuf == NULL)
+ *p_outbuf = gst_buffer_ref (buf);
+}
+
+static gboolean
+run_test (const gchar * path, gint expected_status_code,
+ gboolean has_body, gboolean has_error)
+{
+ GstStateChangeReturn ret;
+ GstElement *pipe, *src, *sink;
+ GstBuffer *buf = NULL;
+ GstMessage *msg;
+ gchar *url;
+ gboolean res = FALSE;
+ GioHttpServer *server;
+ guint port;
+ gboolean done = FALSE;
+
+ server = run_server ();
+ fail_if (server == NULL, "Failed to start up HTTP server");
+
+ pipe = gst_pipeline_new (NULL);
+ fail_unless (pipe != NULL);
+
+ src = gst_element_factory_make ("curlhttpsrc", NULL);
+ fail_unless (src != NULL);
+
+ sink = gst_element_factory_make ("fakesink", NULL);
+ fail_unless (sink != NULL);
+
+ gst_bin_add (GST_BIN (pipe), src);
+ gst_bin_add (GST_BIN (pipe), sink);
+ fail_unless (gst_element_link (src, sink));
+
+ port = get_port_from_server (server);
+ url = g_strdup_printf ("http://127.0.0.1:%u%s", port, path);
+ fail_unless (url != NULL);
+ g_object_set (src, "location", url, NULL);
+ g_free (url);
+
+ g_object_set (src, "automatic-redirect", redirect, NULL);
+ if (cookies != NULL)
+ g_object_set (src, "cookies", cookies, NULL);
+ g_object_set (sink, "signal-handoffs", TRUE, NULL);
+ /*g_object_set (sink, "dump", TRUE, NULL); */
+ g_signal_connect (sink, "preroll-handoff", G_CALLBACK (handoff_cb), &buf);
+
+ ret = gst_element_set_state (pipe, GST_STATE_PAUSED);
+ if (ret != GST_STATE_CHANGE_ASYNC) {
+ GST_DEBUG ("failed to start up curl http src, ret = %d", ret);
+ goto done;
+ }
+
+ gst_element_set_state (pipe, GST_STATE_PLAYING);
+ while (!done) {
+ msg = gst_bus_poll (GST_ELEMENT_BUS (pipe),
+ GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
+ GST_DEBUG ("Message: %" GST_PTR_FORMAT, msg);
+ switch (GST_MESSAGE_TYPE (msg)) {
+ case GST_MESSAGE_ERROR:{
+ gchar *debug = NULL;
+ GError *err = NULL;
+ gint rc = -1;
+ const GstStructure *details = NULL;
+
+ fail_unless (has_error);
+ gst_message_parse_error (msg, &err, &debug);
+ gst_message_parse_error_details (msg, &details);
+ GST_DEBUG ("debug object: %s", debug);
+ GST_DEBUG ("err->message: \"%s\"", err->message);
+ GST_DEBUG ("err->details: %" GST_PTR_FORMAT, details);
+ if (g_str_has_suffix (err->message, "Not Found"))
+ rc = 404;
+ else if (g_str_has_suffix (err->message, "Forbidden"))
+ rc = 403;
+ else if (g_str_has_suffix (err->message, "Unauthorized"))
+ rc = 401;
+ else if (g_str_has_suffix (err->message, "Found"))
+ rc = 302;
+ if (details) {
+ if (gst_structure_has_field_typed (details, "http-status-code",
+ G_TYPE_UINT)) {
+ guint code = 0;
+ gst_structure_get_uint (details, "http-status-code", &code);
+ rc = code;
+ }
+ }
+ g_error_free (err);
+ g_free (debug);
+ GST_DEBUG ("Got HTTP error %d, expected_status_code %d", rc,
+ expected_status_code);
+ res = (rc == expected_status_code);
+ done = TRUE;
+ }
+ break;
+ case GST_MESSAGE_EOS:
+ if (!has_error)
+ done = TRUE;
+ break;
+ default:
+ fail_if (TRUE, "Unexpected GstMessage");
+ break;
+ }
+ gst_message_unref (msg);
+ }
+
+ /* don't wait for more than 10 seconds */
+ ret = gst_element_get_state (pipe, NULL, NULL, 10 * GST_SECOND);
+ GST_LOG ("ret = %u", ret);
+
+ if (buf != NULL) {
+ fail_unless (has_body);
+ /* we want to test the buffer offset, nothing else; if there's a failure
+ * it might be for lots of reasons (no network connection, whatever), we're
+ * not interested in those */
+ GST_DEBUG ("buffer offset = %" G_GUINT64_FORMAT, GST_BUFFER_OFFSET (buf));
+
+ /* first buffer should have a 0 offset */
+ fail_unless (GST_BUFFER_OFFSET (buf) == 0);
+ gst_buffer_unref (buf);
+ }
+ res = TRUE;
+
+done:
+
+ gst_element_set_state (pipe, GST_STATE_NULL);
+ gst_object_unref (pipe);
+ stop_server (server);
+ return res;
+}
+
+GST_START_TEST (test_first_buffer_has_offset)
+{
+ fail_unless (run_test ("/", 200, TRUE, FALSE));
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_not_found)
+{
+ fail_unless (run_test ("/404", 404, FALSE, TRUE));
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_not_found_with_data)
+{
+ fail_unless (run_test ("/404-with-data", 404, TRUE, TRUE));
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_forbidden)
+{
+ fail_unless (run_test ("/403", 403, FALSE, TRUE));
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_redirect_no)
+{
+ redirect = FALSE;
+ fail_unless (run_test ("/302", 302, FALSE, FALSE));
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_redirect_yes)
+{
+ redirect = TRUE;
+ fail_unless (run_test ("/302", 200, TRUE, FALSE));
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_cookies)
+{
+ static const char *biscotti[] = { "delacre=yummie", "koekje=lu", NULL };
+ gboolean res;
+
+ cookies = biscotti;
+ res = run_test ("/", 200, TRUE, FALSE);
+ cookies = NULL;
+ fail_unless (res);
+}
+
+GST_END_TEST;
+
+typedef struct _HttpSrcTestDownloader
+{
+ GstElement *bin;
+ GstElement *src;
+ GstElement *sink;
+ GioHttpServer *server;
+ guint count;
+} HttpSrcTestDownloader;
+
+static gboolean
+move_element_to_ready (gpointer user_data)
+{
+ HttpSrcTestDownloader *tp = (HttpSrcTestDownloader *) user_data;
+
+ GST_TRACE_OBJECT (tp->bin, "Move bin to READY state");
+ gst_element_set_state (tp->bin, GST_STATE_READY);
+ return G_SOURCE_REMOVE;
+}
+
+static GstPadProbeReturn
+src_event_probe (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
+{
+ HttpSrcTestDownloader *tp = (HttpSrcTestDownloader *) user_data;
+ GstEvent *event;
+
+ event = gst_pad_probe_info_get_event (info);
+
+ if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
+ GST_DEBUG_OBJECT (tp->bin, "finished last request");
+ g_idle_add (move_element_to_ready, tp);
+ }
+ return GST_PAD_PROBE_OK;
+}
+
+static void
+start_next_download (HttpSrcTestDownloader * tp)
+{
+ gchar *url;
+
+ url = g_strdup_printf ("http://127.0.0.1:%u/multi/%s-%u",
+ tp->server->port, GST_ELEMENT_NAME (tp->bin), tp->count);
+ fail_unless (url != NULL);
+ GST_DEBUG_OBJECT (tp->bin, "Start next request for: %s", url);
+ g_object_set (tp->src, "location", url, NULL);
+ g_free (url);
+ fail_unless (gst_element_sync_state_with_parent (tp->bin));
+}
+
+static HttpSrcTestDownloader *
+test_curl_http_src_create_downloader (const gchar * name, guint64 delay)
+{
+ HttpSrcTestDownloader *tp;
+ gchar *url;
+ GstPad *src_pad;
+
+ tp = g_slice_new0 (HttpSrcTestDownloader);
+ tp->server = run_server ();
+ fail_if (tp->server == NULL, "Failed to start up HTTP server");
+ tp->server->delay = delay;
+
+ tp->src = gst_element_factory_make ("curlhttpsrc", NULL);
+ fail_unless (tp->src != NULL);
+
+ url = g_strdup_printf ("http://127.0.0.1:%u/multi/%s-0", tp->server->port,
+ name);
+ fail_unless (url != NULL);
+ g_object_set (tp->src, "location", url, NULL);
+ g_free (url);
+
+ src_pad = gst_element_get_static_pad (tp->src, "src");
+ fail_unless (src_pad != NULL);
+ gst_pad_add_probe (src_pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
+ src_event_probe, tp, NULL);
+ gst_object_unref (src_pad);
+
+ tp->sink = gst_element_factory_make ("fakesink", NULL);
+ fail_unless (tp->sink != NULL);
+
+ tp->bin = gst_bin_new (name);
+ fail_unless (tp->bin != NULL);
+
+ gst_bin_add (GST_BIN (tp->bin), tp->src);
+ gst_bin_add (GST_BIN (tp->bin), tp->sink);
+ fail_unless (gst_element_link (tp->src, tp->sink));
+ gst_element_set_locked_state (GST_ELEMENT (tp->bin), TRUE);
+
+ return tp;
+}
+
+typedef struct _MultipleHttpRequestsContext
+{
+ GMainLoop *loop;
+ GstElement *pipe;
+ HttpSrcTestDownloader *downloader1;
+ HttpSrcTestDownloader *downloader2;
+ gboolean failed;
+} MultipleHttpRequestsContext;
+
+static gboolean
+bus_message (GstBus * bus, GstMessage * msg, gpointer user_data)
+{
+ MultipleHttpRequestsContext *context =
+ (MultipleHttpRequestsContext *) user_data;
+ gchar *debug;
+ GError *err;
+ GstState newstate;
+ GstState pending;
+ const GstStructure *details;
+
+ GST_TRACE ("Message: %" GST_PTR_FORMAT, msg);
+ switch (GST_MESSAGE_TYPE (msg)) {
+ case GST_MESSAGE_STATE_CHANGED:
+ gst_message_parse_state_changed (msg, NULL, &newstate, &pending);
+ if (newstate == GST_STATE_PLAYING && pending == GST_STATE_VOID_PENDING &&
+ GST_MESSAGE_SRC (msg) == GST_OBJECT (context->pipe)) {
+ GST_DEBUG ("Test ready to start");
+ start_next_download (context->downloader1);
+ start_next_download (context->downloader2);
+ } else if (newstate == GST_STATE_READY
+ && pending == GST_STATE_VOID_PENDING) {
+ if (GST_MESSAGE_SRC (msg) == GST_OBJECT (context->downloader1->bin)) {
+ if (++context->downloader1->count < 20) {
+ start_next_download (context->downloader1);
+ } else {
+ gst_element_set_state (context->downloader1->bin, GST_STATE_NULL);
+ if (context->downloader2->count == 20) {
+ g_main_loop_quit (context->loop);
+ }
+ }
+ } else if (GST_MESSAGE_SRC (msg) ==
+ GST_OBJECT (context->downloader2->bin)) {
+ if (++context->downloader2->count < 20) {
+ start_next_download (context->downloader2);
+ } else {
+ gst_element_set_state (context->downloader2->bin, GST_STATE_NULL);
+ if (context->downloader1->count == 20) {
+ g_main_loop_quit (context->loop);
+ }
+ }
+ }
+ }
+ break;
+ case GST_MESSAGE_ERROR:
+ debug = NULL;
+ err = NULL;
+ details = NULL;
+ gst_message_parse_error (msg, &err, &debug);
+ gst_message_parse_error_details (msg, &details);
+ GST_DEBUG ("err->debug: %s", debug);
+ GST_DEBUG ("err->message: \"%s\"", err->message);
+ GST_DEBUG ("err->details: %" GST_PTR_FORMAT, details);
+ g_error_free (err);
+ g_free (debug);
+ context->failed = TRUE;
+ g_main_loop_quit (context->loop);
+ break;
+ case GST_MESSAGE_EOS:
+ if (context->downloader1->count == 20
+ && context->downloader2->count == 20) {
+ g_main_loop_quit (context->loop);
+ }
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+/* test_multiple_http_requests tries to reproduce the way in which
+ * GstAdaptiveDemux makes use of URI source elements. GstAdaptiveDemux
+ * creates a bin with the httpsrc element and a queue element and sets the
+ * locked state of that bin to TRUE, so that it does not follow the state
+ * transitions of its parent. It then moves this bin to the PLAYING state
+ * to start each download and back to READY when the download completes.
+ */
+GST_START_TEST (test_multiple_http_requests)
+{
+ GstStateChangeReturn ret;
+ MultipleHttpRequestsContext context;
+ guint watch_id;
+ GstBus *bus;
+
+ context.loop = g_main_loop_new (NULL, FALSE);
+ context.downloader1 =
+ test_curl_http_src_create_downloader ("bin1", 5 * G_USEC_PER_SEC / 1000);
+ fail_unless (context.downloader1 != NULL);
+ context.downloader2 =
+ test_curl_http_src_create_downloader ("bin2", 7 * G_USEC_PER_SEC / 1000);
+ fail_unless (context.downloader2 != NULL);
+
+ context.pipe = gst_pipeline_new (NULL);
+ fail_unless (context.pipe != NULL);
+
+ gst_bin_add (GST_BIN_CAST (context.pipe), context.downloader1->bin);
+ gst_bin_add (GST_BIN_CAST (context.pipe), context.downloader2->bin);
+
+ bus = gst_pipeline_get_bus (GST_PIPELINE (context.pipe));
+ watch_id = gst_bus_add_watch (bus, bus_message, &context);
+ gst_object_unref (bus);
+
+ GST_DEBUG ("Start pipeline playing");
+ ret = gst_element_set_state (context.pipe, GST_STATE_PLAYING);
+ fail_unless (ret == GST_STATE_CHANGE_ASYNC
+ || ret == GST_STATE_CHANGE_SUCCESS);
+
+ g_main_loop_run (context.loop);
+ g_source_remove (watch_id);
+ gst_element_set_state (context.pipe, GST_STATE_NULL);
+ gst_object_unref (context.pipe);
+ stop_server (context.downloader1->server);
+ stop_server (context.downloader2->server);
+ g_slice_free (HttpSrcTestDownloader, context.downloader1);
+ g_slice_free (HttpSrcTestDownloader, context.downloader2);
+ g_main_loop_unref (context.loop);
+}
+
+GST_END_TEST;
+
+static Suite *
+curlhttpsrc_suite (void)
+{
+ TCase *tc_chain;
+ Suite *s;
+
+ /* we don't support exceptions from the proxy, so just unset the environment
+ * variable - in case it's set in the test environment it would otherwise
+ * prevent us from connecting to localhost (like jenkins.qa.ubuntu.com) */
+ g_unsetenv ("http_proxy");
+
+ s = suite_create ("curlhttpsrc");
+ tc_chain = tcase_create ("general");
+
+ suite_add_tcase (s, tc_chain);
+ tcase_add_test (tc_chain, test_first_buffer_has_offset);
+ tcase_add_test (tc_chain, test_redirect_yes);
+ tcase_add_test (tc_chain, test_redirect_no);
+ tcase_add_test (tc_chain, test_not_found);
+ tcase_add_test (tc_chain, test_not_found_with_data);
+ tcase_add_test (tc_chain, test_forbidden);
+ tcase_add_test (tc_chain, test_cookies);
+ tcase_add_test (tc_chain, test_multiple_http_requests);
+
+ return s;
+}
+
+GST_CHECK_MAIN (curlhttpsrc);