checks: add multi-thread test for tagsetter
[platform/upstream/gstreamer.git] / tests / check / gst / gsttagsetter.c
1 /* GStreamer GstTagSetter interface unit tests
2  * Copyright (C) 2007 Tim-Philipp Müller <tim centricular net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <gst/check/gstcheck.h>
21 #include <gst/gst.h>
22 #include <string.h>
23
24 /* some minimal GstTagSetter object */
25 #define GST_TYPE_DUMMY_ENC gst_dummy_enc_get_type()
26
27 typedef GstElement GstDummyEnc;
28 typedef GstElementClass GstDummyEncClass;
29
30 static void gst_dummy_enc_add_interfaces (GType enc_type);
31
32 GType gst_dummy_enc_get_type (void);
33 GST_BOILERPLATE_FULL (GstDummyEnc, gst_dummy_enc, GstElement,
34     GST_TYPE_ELEMENT, gst_dummy_enc_add_interfaces);
35
36 static void
37 gst_dummy_enc_add_interfaces (GType enc_type)
38 {
39   static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
40
41   g_type_add_interface_static (enc_type, GST_TYPE_TAG_SETTER, &tag_setter_info);
42 }
43
44 static void
45 gst_dummy_enc_base_init (gpointer g_class)
46 {
47 }
48
49 static void
50 gst_dummy_enc_class_init (GstDummyEncClass * klass)
51 {
52 }
53
54 static void
55 gst_dummy_enc_init (GstDummyEnc * enc, GstDummyEncClass * klass)
56 {
57 }
58
59 static void
60 tag_list_foreach (const GstTagList * taglist, const gchar * tag, guint * p_num)
61 {
62   guint tag_size;
63
64   tag_size = gst_tag_list_get_tag_size (taglist, tag);
65   GST_LOG ("%u+%u tag = %s", *p_num, tag_size, tag);
66   *p_num += tag_size;
67 }
68
69 static guint
70 tag_setter_list_length (GstTagSetter * setter)
71 {
72   guint len = 0;
73
74   if (gst_tag_setter_get_tag_list (setter) == NULL)
75     return 0;
76
77   gst_tag_list_foreach (gst_tag_setter_get_tag_list (setter),
78       (GstTagForeachFunc) tag_list_foreach, &len);
79   return len;
80 }
81
82 static guint
83 tag_list_length (const GstTagList * tag_list)
84 {
85   guint len = 0;
86
87   if (tag_list == NULL)
88     return 0;
89
90   gst_tag_list_foreach (tag_list, (GstTagForeachFunc) tag_list_foreach, &len);
91   return len;
92 }
93
94 #define assert_tag_setter_list_length(setter,len) \
95     fail_unless_equals_int (tag_setter_list_length(setter), len);
96
97 GST_START_TEST (test_merge)
98 {
99   GstTagSetter *setter;
100   GstTagList *list1, *list2;
101   GstElement *enc;
102
103   enc = g_object_new (GST_TYPE_DUMMY_ENC, NULL);
104   fail_unless (enc != NULL);
105
106   setter = GST_TAG_SETTER (enc);
107
108   list1 = gst_tag_list_new ();
109   gst_tag_list_add (list1, GST_TAG_MERGE_APPEND, GST_TAG_ARTIST, "artist1",
110       NULL);
111   gst_tag_setter_merge_tags (setter, list1, GST_TAG_MERGE_APPEND);
112   assert_tag_setter_list_length (setter, 1);
113
114   list2 = gst_tag_list_new ();
115   gst_tag_list_add (list2, GST_TAG_MERGE_APPEND, GST_TAG_ARTIST, "artist2",
116       GST_TAG_TITLE, "title1", NULL);
117   gst_tag_setter_merge_tags (setter, list2, GST_TAG_MERGE_APPEND);
118   assert_tag_setter_list_length (setter, 3);
119
120   gst_tag_setter_merge_tags (setter, list2, GST_TAG_MERGE_REPLACE_ALL);
121   assert_tag_setter_list_length (setter, 2);
122
123   gst_tag_setter_merge_tags (setter, list1, GST_TAG_MERGE_REPLACE_ALL);
124   assert_tag_setter_list_length (setter, 1);
125
126   gst_tag_setter_add_tags (setter, GST_TAG_MERGE_APPEND, GST_TAG_ALBUM, "xyz",
127       NULL);
128   assert_tag_setter_list_length (setter, 2);
129
130   gst_tag_list_free (list2);
131   gst_tag_list_free (list1);
132
133   g_object_unref (enc);
134 }
135
136 GST_END_TEST
137 GST_START_TEST (test_merge_modes)
138 {
139   GstTagMergeMode mode;
140
141   for (mode = GST_TAG_MERGE_REPLACE_ALL; mode < GST_TAG_MERGE_COUNT; mode++) {
142     gint i;
143
144     for (i = 0; i < 4; i++) {
145       GstElement *enc;
146       GstTagSetter *setter;
147       GstTagList *list1, *list2, *merged;
148
149       enc = g_object_new (GST_TYPE_DUMMY_ENC, NULL);
150       fail_unless (enc != NULL);
151
152       setter = GST_TAG_SETTER (enc);
153       list1 = gst_tag_list_new ();
154       list2 = gst_tag_list_new ();
155
156       /* i = 0: -     -
157        * i = 1: list1 -
158        * i = 2: -     list2
159        * i = 3: list1 list2 */
160
161       if (i % 2 == 1) {
162         gst_tag_list_add (list1, GST_TAG_MERGE_APPEND, GST_TAG_ARTIST,
163             "artist1", NULL);
164       }
165       if (i > 1) {
166         gst_tag_list_add (list2, GST_TAG_MERGE_APPEND, GST_TAG_ARTIST,
167             "artist2", NULL);
168       }
169
170       gst_tag_setter_merge_tags (setter, list1, GST_TAG_MERGE_APPEND);
171       gst_tag_setter_merge_tags (setter, list2, mode);
172
173       merged = gst_tag_list_merge (list1, list2, mode);
174
175       fail_unless_equals_int (tag_list_length (gst_tag_setter_get_tag_list
176               (setter)), tag_list_length (merged));
177
178       gst_tag_list_free (list1);
179       gst_tag_list_free (list2);
180       gst_tag_list_free (merged);
181       gst_object_unref (enc);
182     }
183   }
184 }
185
186 GST_END_TEST
187 GST_START_TEST (test_merge_modes_skip_empty)
188 {
189   GstTagMergeMode mode;
190
191   for (mode = GST_TAG_MERGE_REPLACE_ALL; mode < GST_TAG_MERGE_COUNT; mode++) {
192     gint i;
193
194     for (i = 0; i < 2; i++) {
195       GstElement *enc;
196       GstTagSetter *setter;
197       GstTagList *list1, *list2, *merged;
198
199       enc = g_object_new (GST_TYPE_DUMMY_ENC, NULL);
200       fail_unless (enc != NULL);
201
202       setter = GST_TAG_SETTER (enc);
203       list1 = gst_tag_list_new ();
204       list2 = gst_tag_list_new ();
205
206       if (i == 1) {
207         gst_tag_list_add (list2, GST_TAG_MERGE_APPEND, GST_TAG_ARTIST,
208             "artist2", NULL);
209       }
210
211       gst_tag_setter_merge_tags (setter, list2, mode);
212
213       merged = gst_tag_list_merge (list1, list2, mode);
214
215       fail_unless_equals_int (tag_list_length (gst_tag_setter_get_tag_list
216               (setter)), tag_list_length (merged));
217
218       gst_tag_list_free (list1);
219       gst_tag_list_free (list2);
220       gst_tag_list_free (merged);
221       gst_object_unref (enc);
222     }
223   }
224 }
225
226 GST_END_TEST static int spin_and_wait = 1;
227 static int threads_running = 0;
228
229 #define THREADS_CYCLES 1000
230
231 static gpointer
232 test_threads_thread_func1 (gpointer data)
233 {
234   GstTagSetter *setter = GST_TAG_SETTER (data);
235   int i;
236
237   g_atomic_int_inc (&threads_running);
238   while (g_atomic_int_get (&spin_and_wait))
239     g_usleep (0);
240
241   GST_INFO ("Go!");
242
243   for (i = 0; i < THREADS_CYCLES; ++i) {
244     gst_tag_setter_add_tags (setter, GST_TAG_MERGE_APPEND, GST_TAG_ARTIST,
245         "some artist", GST_TAG_TITLE, "some title", GST_TAG_TRACK_NUMBER, 6,
246         NULL);
247   }
248
249   GST_INFO ("Done");
250
251   return NULL;
252 }
253
254 static gpointer
255 test_threads_thread_func2 (gpointer data)
256 {
257   GstTagSetter *setter = GST_TAG_SETTER (data);
258   int i;
259
260   g_atomic_int_inc (&threads_running);
261   while (g_atomic_int_get (&spin_and_wait))
262     g_usleep (0);
263
264   GST_INFO ("Go!");
265
266   for (i = 0; i < THREADS_CYCLES; ++i) {
267     gst_tag_setter_add_tags (setter, GST_TAG_MERGE_PREPEND, GST_TAG_CODEC,
268         "MP42", GST_TAG_COMMENT, "deep insights go here", GST_TAG_TRACK_COUNT,
269         10, NULL);
270   }
271
272   GST_INFO ("Done");
273
274   return NULL;
275 }
276
277 static gpointer
278 test_threads_thread_func3 (gpointer data)
279 {
280   GstTagSetter *setter = GST_TAG_SETTER (data);
281   int i;
282
283   g_atomic_int_inc (&threads_running);
284   while (g_atomic_int_get (&spin_and_wait))
285     g_usleep (0);
286
287   GST_INFO ("Go!");
288
289   for (i = 0; i < THREADS_CYCLES; ++i) {
290     gst_tag_setter_reset_tags (setter);
291     g_usleep (10);
292   }
293
294   GST_INFO ("Done");
295
296   return NULL;
297 }
298
299 GST_START_TEST (test_threads)
300 {
301   GstTagSetter *setter;
302   GThread *threads[3];
303
304   setter = GST_TAG_SETTER (g_object_new (GST_TYPE_DUMMY_ENC, NULL));
305
306   spin_and_wait = TRUE;
307   threads[0] = g_thread_create (test_threads_thread_func1, setter, TRUE, NULL);
308   threads[1] = g_thread_create (test_threads_thread_func2, setter, TRUE, NULL);
309   threads[2] = g_thread_create (test_threads_thread_func3, setter, TRUE, NULL);
310
311   while (g_atomic_int_get (&threads_running) < 3)
312     g_usleep (10);
313
314   g_atomic_int_set (&spin_and_wait, FALSE);
315
316   g_thread_join (threads[0]);
317   g_thread_join (threads[1]);
318   g_thread_join (threads[2]);
319
320   g_object_unref (G_OBJECT (setter));
321 }
322
323 GST_END_TEST static Suite *
324 gst_tag_setter_suite (void)
325 {
326   Suite *s = suite_create ("GstTagSetter");
327   TCase *tc_chain = tcase_create ("general");
328
329   suite_add_tcase (s, tc_chain);
330   tcase_add_test (tc_chain, test_merge);
331   tcase_add_test (tc_chain, test_merge_modes);
332   tcase_add_test (tc_chain, test_merge_modes_skip_empty);
333   tcase_add_test (tc_chain, test_threads);
334
335   return s;
336 }
337
338 GST_CHECK_MAIN (gst_tag_setter);