1 /*
2  * Unittest for curlfilesink
3  */
4 
5 #include <gst/check/gstcheck.h>
6 #include <glib/gstdio.h>
7 #include <curl/curl.h>
8 #include <unistd.h>
9 
10 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
11     GST_PAD_SRC,
12     GST_PAD_ALWAYS,
13     GST_STATIC_CAPS_ANY);
14 
15 static GstPad *srcpad;
16 
17 static GstElement *sink;
18 
19 static GstElement *
setup_curlfilesink(void)20 setup_curlfilesink (void)
21 {
22   GST_DEBUG ("setup_curlfilesink");
23   sink = gst_check_setup_element ("curlfilesink");
24   srcpad = gst_check_setup_src_pad (sink, &srctemplate);
25   fail_unless (gst_pad_set_active (srcpad, TRUE));
26 
27   return sink;
28 }
29 
30 static void
cleanup_curlfilesink(GstElement * sink)31 cleanup_curlfilesink (GstElement * sink)
32 {
33   GST_DEBUG ("cleanup_curlfilesink");
34 
35   gst_check_teardown_src_pad (sink);
36   gst_check_teardown_element (sink);
37 }
38 
39 static void
test_verify_file_data(const gchar * dir,gchar * file_name,const gchar * expected_file_content)40 test_verify_file_data (const gchar * dir, gchar * file_name,
41     const gchar * expected_file_content)
42 {
43   GError *err = NULL;
44   gchar *res_file_content = NULL;
45   gchar *path = NULL;
46 
47   path = g_strdup_printf ("%s/%s", dir, file_name);
48   g_free (file_name);
49 
50   if (!g_file_get_contents (path, &res_file_content, NULL, &err)) {
51     GST_WARNING ("Error loading file: %s (%s)", file_name, err->message);
52     g_error_free (err);
53   }
54 
55   fail_unless (res_file_content != NULL);
56 
57   fail_unless (strncmp (res_file_content, expected_file_content,
58           strlen (expected_file_content)) == 0);
59   g_free (res_file_content);
60   g_unlink (path);
61   g_free (path);
62 }
63 
64 static void
test_set_and_play_buffer(const gchar * _data)65 test_set_and_play_buffer (const gchar * _data)
66 {
67   gpointer data = (gpointer) _data;
68   GstBuffer *buffer;
69   gint num_bytes;
70 
71   num_bytes = strlen (data);
72   buffer = gst_buffer_new ();
73   gst_buffer_insert_memory (buffer, 0,
74       gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
75           data, num_bytes, 0, num_bytes, data, NULL));
76 
77   fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
78 }
79 
80 static void
test_set_and_fail_to_play_buffer(const gchar * _data)81 test_set_and_fail_to_play_buffer (const gchar * _data)
82 {
83   gpointer data = (gpointer) _data;
84   GstBuffer *buffer;
85   gint num_bytes;
86 
87   num_bytes = strlen (data);
88   buffer = gst_buffer_new ();
89   gst_buffer_insert_memory (buffer, 0,
90       gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
91           data, num_bytes, 0, num_bytes, data, NULL));
92 
93   fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_ERROR);
94 }
95 
GST_START_TEST(test_properties)96 GST_START_TEST (test_properties)
97 {
98   GstElement *sink;
99   GstCaps *caps;
100   const gchar *location = "file:///tmp/";
101   const gchar *file_contents = "line 1\r\n";
102   gchar *file_name = g_strdup_printf ("curlfilesink_%d", g_random_int ());
103   gchar *res_location = NULL;
104   gchar *res_file_name = NULL;
105   gboolean res_create_dirs = FALSE;
106   gchar *path = NULL;
107 
108   sink = setup_curlfilesink ();
109 
110   g_object_set (G_OBJECT (sink), "location", "mylocation", NULL);
111   g_object_set (G_OBJECT (sink), "file-name", "myfile", NULL);
112   g_object_set (G_OBJECT (sink), "create-dirs", TRUE, NULL);
113 
114   g_object_get (sink,
115       "location", &res_location,
116       "file-name", &res_file_name, "create-dirs", &res_create_dirs, NULL);
117 
118   fail_unless (strncmp (res_location, "mylocation", strlen ("mylocation"))
119       == 0);
120   fail_unless (strncmp (res_file_name, "myfile", strlen ("myfile"))
121       == 0);
122   fail_unless (res_create_dirs == TRUE);
123   g_free (res_location);
124   g_free (res_file_name);
125 
126   /* change properties */
127   g_object_set (G_OBJECT (sink), "location", location, NULL);
128   g_object_set (G_OBJECT (sink), "file-name", file_name, NULL);
129   g_object_set (G_OBJECT (sink), "create-dirs", FALSE, NULL);
130 
131   g_object_get (sink,
132       "location", &res_location,
133       "file-name", &res_file_name, "create-dirs", &res_create_dirs, NULL);
134 
135   fail_unless (strncmp (res_location, location, strlen (location))
136       == 0);
137   fail_unless (strncmp (res_file_name, file_name, strlen (file_name))
138       == 0);
139   fail_unless (res_create_dirs == FALSE);
140   g_free (res_location);
141   g_free (res_file_name);
142 
143   /* start playing */
144   ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
145   caps = gst_caps_from_string ("application/x-gst-check");
146   gst_check_setup_events (srcpad, sink, caps, GST_FORMAT_BYTES);
147 
148   /* setup buffer */
149   test_set_and_play_buffer (file_contents);
150 
151   /* try to change location property while in PLAYING state */
152   g_object_set (G_OBJECT (sink), "location", "newlocation", NULL);
153   g_object_get (sink, "location", &res_location, NULL);
154 
155   /* verify that location has not been altered */
156   fail_unless (strncmp (res_location, location, strlen (location))
157       == 0);
158   g_free (res_location);
159 
160   /* eos */
161   fail_unless (gst_pad_push_event (srcpad, gst_event_new_eos ()));
162   ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
163 
164   gst_caps_unref (caps);
165   cleanup_curlfilesink (sink);
166 
167   path = g_strdup_printf ("/tmp/%s", file_name);
168   g_unlink (path);
169   g_free (file_name);
170   g_free (path);
171 }
172 
173 GST_END_TEST;
174 
GST_START_TEST(test_one_file)175 GST_START_TEST (test_one_file)
176 {
177   GstElement *sink;
178   GstCaps *caps;
179   const gchar *location = "file:///tmp/";
180   gchar *file_name = g_strdup_printf ("curlfilesink_%d", g_random_int ());
181   const gchar *file_content = "line 1\r\n";
182   gchar *res_location = NULL;
183   gchar *res_file_name = NULL;
184 
185   sink = setup_curlfilesink ();
186 
187   g_object_set (G_OBJECT (sink), "location", location, NULL);
188   g_object_set (G_OBJECT (sink), "file-name", file_name, NULL);
189 
190   g_object_get (sink,
191       "location", &res_location, "file-name", &res_file_name, NULL);
192 
193   fail_unless (strncmp (res_location, location, strlen (location))
194       == 0);
195   fail_unless (strncmp (res_file_name, file_name, strlen (file_name))
196       == 0);
197 
198   g_free (res_location);
199   g_free (res_file_name);
200 
201   /* start playing */
202   ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
203   caps = gst_caps_from_string ("application/x-gst-check");
204   gst_check_setup_events (srcpad, sink, caps, GST_FORMAT_BYTES);
205 
206   /* setup buffer */
207   test_set_and_play_buffer (file_content);
208 
209   /* eos */
210   fail_unless (gst_pad_push_event (srcpad, gst_event_new_eos ()));
211   ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
212 
213   gst_caps_unref (caps);
214   cleanup_curlfilesink (sink);
215 
216   /* verify file content */
217   test_verify_file_data ("/tmp", file_name, file_content);
218 }
219 
220 GST_END_TEST;
221 
GST_START_TEST(test_one_big_file)222 GST_START_TEST (test_one_big_file)
223 {
224   GstElement *sink;
225   GstCaps *caps;
226   const gchar *location = "file:///tmp/";
227   gchar *file_name = g_strdup_printf ("curlfilesink_%d", g_random_int ());
228   const gchar *file_line1 = "line 1\r\n";
229   const gchar *file_line2 = "line 2\r\n";
230   const gchar *file_line3 = "line 3\r\n";
231   const gchar *expected_file_content = "line 1\r\n" "line 2\r\n" "line 3\r\n";
232   gchar *res_location = NULL;
233   gchar *res_file_name = NULL;
234 
235   sink = setup_curlfilesink ();
236 
237   g_object_set (G_OBJECT (sink), "location", location, NULL);
238   g_object_set (G_OBJECT (sink), "file-name", file_name, NULL);
239 
240   g_object_get (sink,
241       "location", &res_location, "file-name", &res_file_name, NULL);
242 
243   fail_unless (strncmp (res_location, location, strlen (location))
244       == 0);
245   fail_unless (strncmp (res_file_name, file_name, strlen (file_name))
246       == 0);
247 
248   g_free (res_location);
249   g_free (res_file_name);
250 
251   /* start playing */
252   ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
253   caps = gst_caps_from_string ("application/x-gst-check");
254   gst_check_setup_events (srcpad, sink, caps, GST_FORMAT_BYTES);
255 
256   /* setup first buffer */
257   test_set_and_play_buffer (file_line1);
258 
259   /* setup second buffer */
260   test_set_and_play_buffer (file_line2);
261 
262   /* setup third buffer */
263   test_set_and_play_buffer (file_line3);
264 
265   /* eos */
266   fail_unless (gst_pad_push_event (srcpad, gst_event_new_eos ()));
267   ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
268 
269   gst_caps_unref (caps);
270   cleanup_curlfilesink (sink);
271 
272   /* verify file content */
273   test_verify_file_data ("/tmp", file_name, expected_file_content);
274 }
275 
276 GST_END_TEST;
277 
GST_START_TEST(test_two_files)278 GST_START_TEST (test_two_files)
279 {
280   GstElement *sink;
281   GstCaps *caps;
282   const gchar *location = "file:///tmp/";
283   gchar *file_name1 = g_strdup_printf ("curlfilesink_%d", g_random_int ());
284   gchar *file_name2 = g_strdup_printf ("curlfilesink_%d", g_random_int ());
285   const gchar *file_content1 = "file content 1\r\n";
286   const gchar *file_content2 = "file content 2\r\n";
287   gchar *res_location = NULL;
288   gchar *res_file_name = NULL;
289 
290   sink = setup_curlfilesink ();
291 
292   g_object_set (G_OBJECT (sink), "location", location, NULL);
293   g_object_set (G_OBJECT (sink), "file-name", file_name1, NULL);
294 
295   g_object_get (sink,
296       "location", &res_location, "file-name", &res_file_name, NULL);
297 
298   fail_unless (strncmp (res_location, location, strlen (location))
299       == 0);
300   fail_unless (strncmp (res_file_name, file_name1, strlen (file_name1))
301       == 0);
302 
303   g_free (res_location);
304   g_free (res_file_name);
305 
306   /* start playing */
307   ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
308   caps = gst_caps_from_string ("application/x-gst-check");
309   gst_check_setup_events (srcpad, sink, caps, GST_FORMAT_BYTES);
310 
311   /* setup first buffer - content of the first file */
312   test_set_and_play_buffer (file_content1);
313 
314   g_object_set (G_OBJECT (sink), "file-name", file_name2, NULL);
315   g_object_get (sink, "file-name", &res_file_name, NULL);
316   fail_unless (strncmp (res_file_name, file_name2, strlen (file_name2))
317       == 0);
318   g_free (res_file_name);
319 
320   /* setup second buffer - content of the second file */
321   test_set_and_play_buffer (file_content2);
322 
323   /* eos */
324   fail_unless (gst_pad_push_event (srcpad, gst_event_new_eos ()));
325   ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
326 
327   gst_caps_unref (caps);
328   cleanup_curlfilesink (sink);
329 
330   /* verify file contents of the first file */
331   test_verify_file_data ("/tmp", file_name1, file_content1);
332   test_verify_file_data ("/tmp", file_name2, file_content2);
333 }
334 
335 GST_END_TEST;
336 
GST_START_TEST(test_create_dirs)337 GST_START_TEST (test_create_dirs)
338 {
339   GstElement *sink;
340   GstCaps *caps;
341   gchar *tmp_dir = g_strdup ("/tmp/curlfilesink_XXXXXX");
342   gchar *sub_dir;
343   gchar *sub_sub_dir;
344   gchar *location;
345   gchar *file_name = g_strdup_printf ("curlfilesink_%d", g_random_int ());
346   const gchar *file_content = "line 1\r\n";
347 
348   /* create temp dir as base dir (mkdtemp saves dir name in tmp_dir) */
349   fail_unless (mkdtemp (tmp_dir) != NULL);
350 
351   /* use sub-sub directory as location */
352   sub_dir = g_strdup_printf ("%s/a", tmp_dir);
353   sub_sub_dir = g_strdup_printf ("%s/b", sub_dir);
354   location = g_strdup_printf ("file://%s/", sub_sub_dir);
355 
356   sink = setup_curlfilesink ();
357 
358   g_object_set (G_OBJECT (sink), "location", location, NULL);
359   g_object_set (G_OBJECT (sink), "file-name", file_name, NULL);
360   g_object_set (G_OBJECT (sink), "create-dirs", TRUE, NULL);
361 
362   /* start playing */
363   ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
364   caps = gst_caps_from_string ("application/x-gst-check");
365   gst_check_setup_events (srcpad, sink, caps, GST_FORMAT_BYTES);
366 
367   /* setup buffer */
368   test_set_and_play_buffer (file_content);
369 
370   /* eos */
371   fail_unless (gst_pad_push_event (srcpad, gst_event_new_eos ()));
372   ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
373 
374   gst_caps_unref (caps);
375   cleanup_curlfilesink (sink);
376 
377   /* verify file content in sub-sub dir created by sink */
378   test_verify_file_data (sub_sub_dir, file_name, file_content);
379 
380   /* remove directories */
381   fail_unless (g_rmdir (sub_sub_dir) == 0);
382   fail_unless (g_rmdir (sub_dir) == 0);
383   fail_unless (g_rmdir (tmp_dir) == 0);
384   g_free (sub_sub_dir);
385   g_free (sub_dir);
386   g_free (tmp_dir);
387   g_free (location);
388 }
389 
390 GST_END_TEST;
391 
GST_START_TEST(test_missing_path)392 GST_START_TEST (test_missing_path)
393 {
394   GstElement *sink;
395   GstCaps *caps;
396   const gchar *location = "file:///missing/path/";
397   gchar *file_name = g_strdup_printf ("curlfilesink_%d", g_random_int ());
398   const gchar *file_content = "line 1\r\n";
399   gchar *res_location = NULL;
400   gchar *res_file_name = NULL;
401 
402   sink = setup_curlfilesink ();
403 
404   g_object_set (G_OBJECT (sink), "location", location, NULL);
405   g_object_set (G_OBJECT (sink), "file-name", file_name, NULL);
406 
407   g_object_get (sink,
408       "location", &res_location, "file-name", &res_file_name, NULL);
409 
410   fail_unless (strncmp (res_location, location, strlen (location))
411       == 0);
412   fail_unless (strncmp (res_file_name, file_name, strlen (file_name))
413       == 0);
414 
415   g_free (res_location);
416   g_free (res_file_name);
417   g_free (file_name);
418 
419   /* start playing */
420   ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
421   caps = gst_caps_from_string ("application/x-gst-check");
422   gst_check_setup_events (srcpad, sink, caps, GST_FORMAT_BYTES);
423 
424   /* setup & play buffer which should fail due to the missing path */
425   test_set_and_fail_to_play_buffer (file_content);
426 
427   /* eos */
428   fail_unless (gst_pad_push_event (srcpad, gst_event_new_eos ()));
429   ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
430 
431   gst_caps_unref (caps);
432   cleanup_curlfilesink (sink);
433 }
434 
435 GST_END_TEST;
436 
437 static Suite *
curlsink_suite(void)438 curlsink_suite (void)
439 {
440   Suite *s = suite_create ("curlfilesink");
441   TCase *tc_chain = tcase_create ("general");
442 
443   suite_add_tcase (s, tc_chain);
444   tcase_set_timeout (tc_chain, 20);
445   tcase_add_test (tc_chain, test_properties);
446   tcase_add_test (tc_chain, test_one_file);
447   tcase_add_test (tc_chain, test_one_big_file);
448   tcase_add_test (tc_chain, test_two_files);
449   tcase_add_test (tc_chain, test_missing_path);
450   tcase_add_test (tc_chain, test_create_dirs);
451 
452   return s;
453 }
454 
455 GST_CHECK_MAIN (curlsink);
456