Merge lp:~gordallott/unity/unity-ubus into lp:unity

Proposed by Gord Allott
Status: Merged
Approved by: Neil J. Patel
Approved revision: no longer in the source branch.
Merged at revision: 629
Proposed branch: lp:~gordallott/unity/unity-ubus
Merge into: lp:unity
Diff against target: 786 lines (+611/-15)
7 files modified
libunity/CMakeLists.txt (+1/-1)
libunity/ubus-server.c (+361/-0)
libunity/ubus-server.h (+74/-0)
services/panel-service.c (+16/-12)
tests/CMakeLists.txt (+4/-1)
tests/unit/TestMain.cpp (+3/-1)
tests/unit/TestUBus.cpp (+152/-0)
To merge this branch: bzr merge lp:~gordallott/unity/unity-ubus
Reviewer Review Type Date Requested Status
Neil J. Patel (community) Approve
Review via email: mp+41856@code.launchpad.net

Description of the change

adds UBus Support into unity, a simple message broadcasting service to allow for simple inter component communication without introducing dependencies.

Comes with tests because tests are awesome

To post a comment you must log in.
Revision history for this message
Neil J. Patel (njpatel) wrote :

- g_hash_table_destroy does what you want it to and won't break if they use g_slice to allocate hashtable struct in the future

- Tab indenting in a bunch of places

- The first server you create has a ref count of 2 because it's not initially unowned (hence returns from g_object_new with ref_count = 1) and then your ref it again before retuning; Maybe make it derive from GInitiallyUnowned and return g_object_ref_sink (service)

- Like the singleton approach, haven't seen that in a while ;)

review: Needs Fixing
Revision history for this message
Gord Allott (gordallott) wrote :

fixed the hash tab indenting
regarding the reference counting, I think its best to just hold on to our own reference and own it completely, no real reason to start increasing/decreasing the reference count because we can only initialize the object once in the programs lifetime. we want it to stick around :) so i'm just holding on to one reference now and not passing any back to whatever calls get_default ()

Revision history for this message
Neil J. Patel (njpatel) :
review: Approve
Revision history for this message
Mikkel Kamstrup Erlandsen (kamstrup) wrote :

+UBusMessageInfo *
+ubus_message_info_new (const gchar *message, GVariant *data)
+{
+ UBusMessageInfo *info = g_new (UBusMessageInfo, 1);
+ info->message = g_strdup (message);
+ info->data = data;
+
+ if (data != NULL)
+ g_variant_ref (data);
+ return info;
+}

You probably want to g_variant_ref_sink() instead so one can pass a
floating ref to send() without leaking.

+ if (info->data != NULL)
+ g_variant_unref (info->data);
+ g_free (info);

You're leaking the message string. Why not use the
ubus_message_info_free() function you implemented above?

Static modifiers are missing on all private functions in the .c files.
Right now you exporting all the unnamespaced utility functions.

If we expect the message names to not contain variations like
"unity_msg_N" for random 0 < N < 9999999999 then, ie. constant string
like "Unity.ShowDash", then it's a big waste go g_strdup() the message
in the UBusMessageInfo constructor. Just use a GStringChunk and save
all the reallocations.

Other than that nice work :-)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'libunity/CMakeLists.txt'
2--- libunity/CMakeLists.txt 2010-11-19 12:06:29 +0000
3+++ libunity/CMakeLists.txt 2010-11-25 14:26:39 +0000
4@@ -56,7 +56,7 @@
5 GENERATE_VAPI unity
6 )
7
8-add_library (${PKGNAME} SHARED ${VALA_C})
9+add_library (${PKGNAME} SHARED ${VALA_C} ubus-server.c)
10 set_target_properties (${PKGNAME} PROPERTIES
11 VERSION ${libunity_VERSION}
12 SOVERSION ${libunity_SOVERSION}
13
14=== added file 'libunity/ubus-server.c'
15--- libunity/ubus-server.c 1970-01-01 00:00:00 +0000
16+++ libunity/ubus-server.c 2010-11-25 14:26:39 +0000
17@@ -0,0 +1,361 @@
18+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
19+/*
20+ * u-bus-server.c
21+ * Copyright (C) 2010 Canonical, Ltd.
22+ *
23+ * This library is free software; you can redistribute it and/or modify
24+ * it under the terms of the GNU Lesser General Public License
25+ * version 3.0 as published by the Free Software Foundation.
26+ *
27+ * This library is distributed in the hope that it will be useful,
28+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
29+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30+ * GNU Lesser General Public License version 3.0 for more details.
31+ *
32+ * You should have received a copy of the GNU Lesser General Public
33+ * License along with this library. If not, see
34+ * <http://www.gnu.org/licenses/>.
35+ *
36+ * Authored by Gordon Allott <gord.allott@canonical.com>
37+ */
38+
39+#include "ubus-server.h"
40+#include <string.h>
41+#include <stdlib.h>
42+#include <glib.h>
43+
44+#define UBUS_SERVER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
45+ UBUS_TYPE_SERVER, \
46+ UBusServerPrivate))
47+
48+struct _UBusServerPrivate
49+{
50+ GHashTable *message_interest_table;
51+ GHashTable *dispatch_table;
52+
53+ GQueue *message_queue;
54+
55+ gulong id_sequencial_number;
56+ gboolean message_pump_queued;
57+};
58+
59+
60+G_DEFINE_TYPE (UBusServer, ubus_server, G_TYPE_INITIALLY_UNOWNED);
61+
62+struct _UBusDispatchInfo
63+{
64+ gulong id;
65+ UBusCallback callback;
66+ gchar *message;
67+ gpointer *user_data;
68+};
69+typedef struct _UBusDispatchInfo UBusDispatchInfo;
70+
71+UBusDispatchInfo *
72+ubus_dispatch_info_new (UBusServer* server, const gchar *message,
73+ UBusCallback callback, gpointer user_data)
74+{
75+ g_return_val_if_fail (UBUS_IS_SERVER (server), NULL);
76+ UBusServerPrivate *priv = server->priv;
77+ UBusDispatchInfo *info;
78+
79+ if (priv->id_sequencial_number < 1)
80+ {
81+ g_critical (G_STRLOC ": ID's are overflowing");
82+ }
83+
84+ info = g_new (UBusDispatchInfo, 1);
85+ info->id = priv->id_sequencial_number++;
86+ info->callback = callback;
87+ info->message = g_strdup (message);
88+ info->user_data = user_data;
89+
90+ return info;
91+}
92+
93+void
94+ubus_dispatch_info_free (UBusDispatchInfo *info)
95+{
96+ g_free (info->message);
97+ g_free (info);
98+}
99+
100+struct _UBusMessageInfo
101+{
102+ gchar *message;
103+ GVariant *data;
104+};
105+
106+typedef struct _UBusMessageInfo UBusMessageInfo;
107+
108+UBusMessageInfo *
109+ubus_message_info_new (const gchar *message, GVariant *data)
110+{
111+ UBusMessageInfo *info = g_new (UBusMessageInfo, 1);
112+ info->message = g_strdup (message);
113+ info->data = data;
114+
115+ if (data != NULL)
116+ g_variant_ref (data);
117+ return info;
118+}
119+
120+void
121+ubus_message_info_free (UBusMessageInfo *info)
122+{
123+ g_variant_unref (info->data);
124+ g_free (info->message);
125+ g_free (info);
126+}
127+
128+gboolean
129+ulong_equal (gconstpointer v1,
130+ gconstpointer v2)
131+{
132+ return *((const gulong*) v1) == *((const gulong*) v2);
133+}
134+
135+guint
136+ulong_hash (gconstpointer v)
137+{
138+ return (guint) *(const gulong*) v;
139+}
140+
141+static void
142+ubus_server_init (UBusServer *server)
143+{
144+ UBusServerPrivate *priv;
145+ priv = server->priv = UBUS_SERVER_GET_PRIVATE (server);
146+
147+ // message_interest_table holds the message/DispatchInfo relationship
148+ priv->message_interest_table = g_hash_table_new_full (g_str_hash, g_str_equal,
149+ g_free,
150+ (GDestroyNotify)g_sequence_free);
151+ // dispatch table holds the individial id/DispatchInfo pairs
152+ priv->dispatch_table = g_hash_table_new_full (ulong_hash, ulong_equal,
153+ g_free,
154+ (GDestroyNotify)ubus_dispatch_info_free);
155+
156+ // for anyone thats wondering (hi kamstrup!), there are two hash tables so
157+ // that lookups are fast when sending messages and removing handlers
158+
159+ priv->message_queue = g_queue_new ();
160+ priv->id_sequencial_number = 1;
161+}
162+
163+static void
164+ubus_server_finalize (GObject *object)
165+{
166+ UBusServer *server = UBUS_SERVER (object);
167+ UBusServerPrivate *priv = server->priv;
168+ g_hash_table_destroy (priv->message_interest_table);
169+ g_hash_table_destroy (priv->dispatch_table);
170+
171+ UBusMessageInfo *info = g_queue_pop_tail (priv->message_queue);
172+ for (; info != NULL; info = g_queue_pop_tail (priv->message_queue))
173+ {
174+ if (info->data != NULL)
175+ g_variant_unref (info->data);
176+ g_free (info);
177+ }
178+
179+ g_queue_free (priv->message_queue);
180+
181+ G_OBJECT_CLASS (ubus_server_parent_class)->finalize (object);
182+}
183+
184+static void
185+ubus_server_class_init (UBusServerClass *klass)
186+{
187+ GObjectClass* object_class = G_OBJECT_CLASS (klass);
188+ g_type_class_add_private (klass, sizeof (UBusServerPrivate));
189+ object_class->finalize = ubus_server_finalize;
190+}
191+
192+UBusServer *
193+ubus_server_get_default ()
194+{
195+ static gsize singleton;
196+ if (g_once_init_enter (&singleton))
197+ {
198+ UBusServer *server;
199+ server = g_object_new (UBUS_TYPE_SERVER, NULL);
200+ g_object_ref_sink (server);
201+ g_once_init_leave (&singleton, (gsize) server);
202+ }
203+
204+ // we actually just want to hold our own reference and not let anything
205+ // else reference us, because we never want to lose that reference, we are
206+ // only allowed to initalise once
207+ return (UBusServer *)singleton;
208+}
209+
210+gulong
211+ubus_server_register_interest (UBusServer* server, const gchar *message,
212+ UBusCallback callback, gpointer user_data)
213+{
214+ g_return_val_if_fail (UBUS_IS_SERVER (server), 0);
215+ g_return_val_if_fail (message != NULL, 0);
216+
217+ UBusServerPrivate *priv = server->priv;
218+ GSequence *dispatch_list = g_hash_table_lookup (priv->message_interest_table,
219+ message);
220+ UBusDispatchInfo *info;
221+
222+ if (dispatch_list == NULL)
223+ {
224+ // not had this message before so add a new entry to the message_interest table
225+ gchar *key = g_strdup (message);
226+ dispatch_list = g_sequence_new (NULL); // we use a sequence because its a stable pointer
227+ g_hash_table_insert (priv->message_interest_table, key, dispatch_list);
228+ }
229+
230+ // add the callback to the dispatch table
231+ info = ubus_dispatch_info_new (server, message, callback, user_data);
232+ gulong *id = g_malloc (sizeof (gulong));
233+ *id = info->id;
234+ g_hash_table_insert (priv->dispatch_table, id, info);
235+
236+ // add the dispatch info to the dispatch list in the message interest table
237+ g_sequence_append (dispatch_list, info);
238+
239+ return info->id;
240+}
241+
242+gboolean
243+ubus_server_pump_message_queue (UBusServer *server)
244+{
245+ g_return_val_if_fail (UBUS_IS_SERVER (server), FALSE);
246+ UBusServerPrivate *priv = server->priv;
247+ UBusMessageInfo *info;
248+
249+ priv->message_pump_queued = TRUE;
250+
251+ // loop through each message queued and call the dispatch functions associated
252+ // with it. something in the back of my mind says it would be quicker in some
253+ // situations to sort the queue first so that duplicate messages can re-use
254+ // the same dispatch_list lookups.. but thats a specific case.
255+
256+
257+ info = g_queue_pop_tail (priv->message_queue);
258+ for (; info != NULL; info = g_queue_pop_tail (priv->message_queue))
259+ {
260+ GSequence *dispatch_list;
261+ dispatch_list = g_hash_table_lookup (priv->message_interest_table,
262+ info->message);
263+
264+ if (dispatch_list == NULL)
265+ continue; // no handlers for this message
266+
267+ GSequenceIter *iter = g_sequence_get_begin_iter (dispatch_list);
268+ GSequenceIter *end = g_sequence_get_end_iter (dispatch_list);
269+
270+ while (iter != end)
271+ {
272+ GSequenceIter *next = g_sequence_iter_next (iter);
273+ UBusDispatchInfo *dispatch_info = g_sequence_get (iter);
274+ UBusCallback callback = dispatch_info->callback;
275+
276+ (*callback) (info->data, dispatch_info->user_data);
277+
278+ iter = next;
279+ }
280+
281+ if (info->data != NULL)
282+ g_variant_unref (info->data);
283+ g_free (info);
284+ }
285+
286+ return FALSE;
287+}
288+
289+void
290+ubus_server_queue_message_pump (UBusServer *server)
291+{
292+ g_return_if_fail (UBUS_IS_SERVER (server));
293+ UBusServerPrivate *priv = server->priv;
294+
295+ if (priv->message_pump_queued)
296+ return;
297+
298+ g_idle_add ((GSourceFunc)ubus_server_pump_message_queue, server);
299+ priv->message_pump_queued = TRUE;
300+}
301+
302+void
303+ubus_server_send_message (UBusServer *server, const gchar *message,
304+ GVariant *data)
305+{
306+ g_return_if_fail (UBUS_IS_SERVER (server));
307+ g_return_if_fail (message != NULL);
308+ UBusServerPrivate *priv = server->priv;
309+
310+ UBusMessageInfo *message_info = ubus_message_info_new (message, data);
311+ g_queue_push_head (priv->message_queue, message_info);
312+
313+ ubus_server_queue_message_pump (server);
314+}
315+
316+void
317+ubus_server_unregister_interest (UBusServer* server, gulong handle)
318+{
319+ g_return_if_fail (UBUS_IS_SERVER (server));
320+ g_return_if_fail (handle > 0);
321+ UBusServerPrivate *priv = server->priv;
322+ UBusDispatchInfo *info;
323+ GSequence *dispatch_list;
324+
325+ // get our info
326+ info = g_hash_table_lookup (priv->dispatch_table, &handle);
327+
328+ if (info == NULL)
329+ {
330+ g_warning (G_STRLOC ": Handle %lu does not exist", handle);
331+ return;
332+ }
333+
334+ // now the slightly sucky bit, we have to remove from our message-interest
335+ // table, but we can only find it by itterating through a sequence
336+ // but this is not so bad because we know *which* sequence its in
337+
338+ dispatch_list = g_hash_table_lookup (priv->message_interest_table,
339+ info->message);
340+
341+ if (dispatch_list == NULL)
342+ {
343+ g_critical (G_STRLOC ": Handle exists but not dispatch list, ubus has "\
344+ "become unstable");
345+ return;
346+ }
347+
348+ GSequenceIter *iter = g_sequence_get_begin_iter (dispatch_list);
349+ GSequenceIter *end = g_sequence_get_end_iter (dispatch_list);
350+ while (iter != end)
351+ {
352+ GSequenceIter *next = g_sequence_iter_next (iter);
353+ UBusDispatchInfo *info_test = g_sequence_get (iter);
354+
355+ if (info_test->id == handle)
356+ {
357+ g_sequence_remove (iter);
358+ }
359+
360+ iter = next;
361+ }
362+
363+ if (g_sequence_get_length (dispatch_list) == 0)
364+ {
365+ // free the key/value pair
366+ g_hash_table_remove (priv->message_interest_table, info->message);
367+ }
368+
369+ // finally remove the dispatch_table hash table.
370+ g_hash_table_remove (priv->dispatch_table, &handle);
371+
372+}
373+
374+void
375+ubus_server_force_message_pump (UBusServer* server)
376+{
377+ ubus_server_pump_message_queue (server);
378+}
379
380=== added file 'libunity/ubus-server.h'
381--- libunity/ubus-server.h 1970-01-01 00:00:00 +0000
382+++ libunity/ubus-server.h 2010-11-25 14:26:39 +0000
383@@ -0,0 +1,74 @@
384+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
385+/*
386+ * u-bus-server.h
387+ * Copyright (C) 2010 Canonical, Ltd.
388+ *
389+ * This library is free software; you can redistribute it and/or modify
390+ * it under the terms of the GNU Lesser General Public License
391+ * version 3.0 as published by the Free Software Foundation.
392+ *
393+ * This library is distributed in the hope that it will be useful,
394+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
395+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
396+ * GNU Lesser General Public License version 3.0 for more details.
397+ *
398+ * You should have received a copy of the GNU Lesser General Public
399+ * License along with this library. If not, see
400+ * <http://www.gnu.org/licenses/>.
401+ *
402+ * Authored by Gordon Allott <gord.allott@canonical.com>
403+ */
404+
405+#ifndef _U_BUS_SERVER_H_
406+#define _U_BUS_SERVER_H_
407+
408+#include <glib-object.h>
409+#include <glib.h>
410+G_BEGIN_DECLS
411+
412+#define UBUS_TYPE_SERVER (ubus_server_get_type ())
413+#define UBUS_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UBUS_TYPE_SERVER, UBusServer))
414+#define UBUS_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UBUS_TYPE_SERVER, UBusServerClass))
415+#define UBUS_IS_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UBUS_TYPE_SERVER))
416+#define UBUS_IS_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UBUS_TYPE_SERVER))
417+#define UBUS_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UBUS_TYPE_SERVER, UBusServerClass))
418+
419+typedef struct _UBusServerClass UBusServerClass;
420+typedef struct _UBusServer UBusServer;
421+typedef struct _UBusServerPrivate UBusServerPrivate;
422+
423+struct _UBusServerClass
424+{
425+ GObjectClass parent_class;
426+
427+ /* padding */
428+ void (*_unity_padding1) (void);
429+ void (*_unity_padding2) (void);
430+ void (*_unity_padding3) (void);
431+ void (*_unity_padding4) (void);
432+ void (*_unity_padding5) (void);
433+ void (*_unity_padding6) (void);
434+};
435+
436+struct _UBusServer
437+{
438+ GObject parent_instance;
439+
440+ UBusServerPrivate *priv;
441+};
442+
443+typedef void (*UBusCallback) (GVariant *data, gpointer *user_data);
444+
445+GType ubus_server_get_type (void) G_GNUC_CONST;
446+UBusServer *ubus_server_get_default ();
447+void ubus_server_prime_context (UBusServer* server, GMainContext *context);
448+gulong ubus_server_register_interest (UBusServer* server, const gchar *message,
449+ UBusCallback callback, gpointer user_data);
450+void ubus_server_send_message (UBusServer* server, const gchar *message,
451+ GVariant *data);
452+void ubus_server_unregister_interest (UBusServer* server, gulong handle);
453+void ubus_server_force_message_pump (UBusServer* server);
454+
455+G_END_DECLS
456+
457+#endif /* _U_BUS_SERVER_H_ */
458
459=== modified file 'services/panel-service.c'
460--- services/panel-service.c 2010-11-17 23:53:21 +0000
461+++ services/panel-service.c 2010-11-25 14:26:39 +0000
462@@ -158,7 +158,7 @@
463 GdkWindow *window = gtk_widget_get_window (GTK_WIDGET (self->priv->last_menu));
464 if (window == NULL)
465 return GDK_FILTER_CONTINUE;
466-
467+
468 Window xwindow = gdk_x11_drawable_get_xid (GDK_DRAWABLE (window));
469
470 if (xwindow == 0)
471@@ -236,7 +236,10 @@
472 static gboolean
473 initial_resync (PanelService *self)
474 {
475- g_signal_emit (self, _service_signals[RE_SYNC], 0, "");
476+ if (PANEL_IS_SERVICE (self))
477+ g_signal_emit (self, _service_signals[RE_SYNC], 0, "");
478+
479+
480 return FALSE;
481 }
482
483@@ -264,7 +267,7 @@
484 panel_service_get_default ()
485 {
486 static PanelService *service = NULL;
487-
488+
489 if (service == NULL || !PANEL_IS_SERVICE (service))
490 service = g_object_new (PANEL_TYPE_SERVICE, NULL);
491
492@@ -293,13 +296,14 @@
493
494 return g_slist_length (self->priv->indicators);
495 }
496-
497+
498 /*
499 * Private Methods
500 */
501 static gboolean
502 actually_notify_object (IndicatorObject *object)
503 {
504+ if (!INDICATOR_IS_OBJECT (object)) return;
505 PanelService *self;
506 PanelServicePrivate *priv;
507 gint position;
508@@ -310,7 +314,7 @@
509 position = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (object), "position"));
510 priv->timeouts[position] = SYNC_WAITING;
511
512- if (!suppress_signals);
513+ if (!suppress_signals)
514 g_signal_emit (self, _service_signals[RE_SYNC],
515 0, g_object_get_data (G_OBJECT (object), "id"));
516
517@@ -392,7 +396,7 @@
518 G_CALLBACK (on_entry_changed), object);
519 g_signal_connect (entry->label, "hide",
520 G_CALLBACK (on_entry_changed), object);
521-
522+
523 }
524 if (GTK_IS_IMAGE (entry->image))
525 {
526@@ -452,7 +456,7 @@
527 priv->indicators = g_slist_append (priv->indicators, object);
528
529 g_object_set_data_full (G_OBJECT (object), "id", g_strdup (name), g_free);
530-
531+
532 g_signal_connect (object, INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED,
533 G_CALLBACK (on_entry_added), self);
534 g_signal_connect (object, INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED,
535@@ -535,7 +539,7 @@
536
537 s1 = g_object_get_data (G_OBJECT (o1), "id");
538 s2 = g_object_get_data (G_OBJECT (o2), "id");
539-
540+
541 i1 = name2order (s1);
542 i2 = name2order (s2);
543
544@@ -573,7 +577,7 @@
545 GError *error = NULL;
546
547 pixbuf = gtk_image_get_pixbuf (image);
548-
549+
550 if (gdk_pixbuf_save_to_buffer (pixbuf, &buffer, &buffer_size, "png", &error, NULL))
551 {
552 ret = g_base64_encode ((const guchar *)buffer, buffer_size);
553@@ -623,7 +627,7 @@
554 gboolean is_label = GTK_IS_LABEL (entry->label);
555 gboolean is_image = GTK_IS_IMAGE (entry->image);
556 gchar *image_data = NULL;
557-
558+
559 g_variant_builder_add (b, "(sssbbusbb)",
560 indicator_id,
561 id,
562@@ -729,7 +733,7 @@
563 /* Set the sync back to neutral */
564 position = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (i->data), "position"));
565 self->priv->timeouts[position] = SYNC_NEUTRAL;
566-
567+
568 indicator_object_to_variant (i->data, indicator_id, &b);
569 }
570
571@@ -776,7 +780,7 @@
572 {
573 PanelServicePrivate *priv = self->priv;
574 IndicatorObjectEntry *entry = g_hash_table_lookup (priv->id2entry_hash, entry_id);
575-
576+
577 if (GTK_IS_MENU (priv->last_menu))
578 {
579 priv->last_x = 0;
580
581=== modified file 'tests/CMakeLists.txt'
582--- tests/CMakeLists.txt 2010-11-24 16:36:23 +0000
583+++ tests/CMakeLists.txt 2010-11-25 14:26:39 +0000
584@@ -16,7 +16,7 @@
585 ${TEST_UNIT_DEPS_CFLAGS_OTHER}
586 "-DGETTEXT_PACKAGE=\"unity\""
587 "-DINDICATORDIR=\"${CMAKE_BINARY_DIR}/tests\""
588- "-DINDICATORICONDIR=\"${CMAKE_BINARY_DIR}/tests\""
589+ "-DINDICATORICONDIR=\"${CMAKE_BINARY_DIR}/tests\""
590 )
591 add_definitions (${CFLAGS})
592
593@@ -35,6 +35,9 @@
594 unit/TestFavoriteStoreGSettings.cpp
595 unit/TestPanelService.cpp
596 unit/TestMain.cpp
597+ unit/TestUBus.cpp
598+ ../libunity/ubus-server.c
599+ ../libunity/ubus-server.h
600 ../services/panel-service.c
601 ../services/panel-service.h
602 ../src/FavoriteStore.cpp
603
604=== modified file 'tests/unit/TestMain.cpp'
605--- tests/unit/TestMain.cpp 2010-11-17 21:38:57 +0000
606+++ tests/unit/TestMain.cpp 2010-11-25 14:26:39 +0000
607@@ -24,6 +24,7 @@
608
609 void TestFavoriteStoreGSettingsCreateSuite (void);
610 void TestPanelServiceCreateSuite (void);
611+void TestUBusCreateSuite (void);
612
613 int
614 main (int argc, char **argv)
615@@ -32,12 +33,13 @@
616
617 g_type_init ();
618 g_thread_init (NULL);
619-
620+
621 g_test_init (&argc, &argv, NULL);
622
623 //Keep alphabetical please
624 TestFavoriteStoreGSettingsCreateSuite ();
625 TestPanelServiceCreateSuite ();
626+ TestUBusCreateSuite ();
627
628 return g_test_run ();
629 }
630
631=== added file 'tests/unit/TestUBus.cpp'
632--- tests/unit/TestUBus.cpp 1970-01-01 00:00:00 +0000
633+++ tests/unit/TestUBus.cpp 2010-11-25 14:26:39 +0000
634@@ -0,0 +1,152 @@
635+/*
636+ * Copyright 2010 Canonical Ltd.
637+ *
638+ * This program is free software: you can redistribute it and/or modify it
639+ * under the terms of the GNU General Public License version 3, as published
640+ * by the Free Software Foundation.
641+ *
642+ * This program is distributed in the hope that it will be useful, but
643+ * WITHOUT ANY WARRANTY; without even the implied warranties of
644+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
645+ * PURPOSE. See the GNU General Public License for more details.
646+ *
647+ * You should have received a copy of the GNU General Public License
648+ * version 3 along with this program. If not, see
649+ * <http://www.gnu.org/licenses/>
650+ *
651+ * Authored by: Gordon Allott <gord.allott@canonical.com>
652+ *
653+ */
654+
655+
656+#include "config.h"
657+#include "libunity/ubus-server.h"
658+
659+#define MESSAGE1 "TEST MESSAGE ONE"
660+#define MESSAGE2 "ՄᕅᏆⲤꙨႧΈ Ϊટ ಗשׁຣ໐ɱË‼‼❢"
661+
662+static void TestAllocation (void);
663+static void TestMainLoop (void);
664+static void TestPropagation (void);
665+
666+void
667+TestUBusCreateSuite ()
668+{
669+#define _DOMAIN "/Unit/UBus"
670+ g_test_add_func (_DOMAIN"/Allocation", TestAllocation);
671+ g_test_add_func (_DOMAIN"/Propagation", TestPropagation);
672+ g_test_add_func (_DOMAIN"/MainLoop", TestMainLoop);
673+}
674+
675+static void
676+TestAllocation ()
677+{
678+ UBusServer *serv_1 = ubus_server_get_default ();
679+ UBusServer *serv_2 = ubus_server_get_default ();
680+
681+ g_assert (serv_1 != NULL);
682+ g_assert (serv_2 != NULL);
683+
684+ // i used a different way of making a singleton than i am used to
685+ // so i'm not 100% confident in it yet
686+ g_assert (serv_1 == serv_2);
687+}
688+
689+void
690+test_handler_inc_counter (GVariant *data, gpointer *val)
691+{
692+ // inc a counter when we get called
693+ gint *counter = (gint*)val;
694+ *counter = *counter + 1;
695+}
696+
697+void
698+test_handler_inc_counter_2 (GVariant *data, gpointer *val)
699+{
700+ // inc a counter by two when called
701+ gint *counter = (gint*)val;
702+ *counter = *counter + 2;
703+}
704+
705+static void
706+TestPropagation ()
707+{
708+ UBusServer *ubus = ubus_server_get_default ();
709+ gint counter = 0;
710+ gulong handler1 = ubus_server_register_interest (ubus, MESSAGE1,
711+ test_handler_inc_counter,
712+ &counter);
713+
714+ gulong handler2 = ubus_server_register_interest (ubus, MESSAGE2, // tests UNICODE
715+ test_handler_inc_counter_2,
716+ &counter);
717+
718+ gint i;
719+ for (i=0; i<1000; i++)
720+ {
721+ ubus_server_send_message (ubus, MESSAGE1, NULL);
722+ }
723+
724+ ubus_server_force_message_pump (ubus);
725+
726+ counter = 0;
727+ for (i=0; i<1000; i++)
728+ {
729+ ubus_server_send_message (ubus, MESSAGE1, NULL);
730+ ubus_server_send_message (ubus, MESSAGE2, NULL);
731+ }
732+ ubus_server_force_message_pump (ubus);
733+
734+ g_assert (counter == 3000);
735+
736+ ubus_server_unregister_interest (ubus, handler1);
737+ ubus_server_unregister_interest (ubus, handler2);
738+
739+ counter = 0;
740+ ubus_server_send_message (ubus, MESSAGE1, NULL);
741+ ubus_server_send_message (ubus, MESSAGE2, NULL);
742+
743+ ubus_server_force_message_pump (ubus);
744+
745+ g_assert (counter == 0);
746+}
747+
748+gboolean
749+main_loop_bailout (gpointer data)
750+{
751+ GMainLoop *mainloop = (GMainLoop*)data;
752+ g_main_quit (mainloop);
753+ return FALSE;
754+}
755+
756+void
757+test_handler_mainloop (GVariant *data, gpointer *val)
758+{
759+ // inc a counter when we get called
760+ gint *counter = (gint*)val;
761+ *counter = *counter + 1;
762+
763+}
764+
765+static void
766+TestMainLoop ()
767+{
768+ GMainLoop *mainloop;
769+ UBusServer *ubus = ubus_server_get_default ();
770+ gint counter = 0;
771+
772+ mainloop = g_main_loop_new (NULL, TRUE);
773+ g_timeout_add_seconds (1, main_loop_bailout, mainloop);
774+
775+ ubus_server_register_interest (ubus, MESSAGE1,
776+ test_handler_mainloop,
777+ &counter);
778+
779+ ubus_server_send_message (ubus, MESSAGE1, NULL);
780+ g_main_loop_run (mainloop);
781+
782+ g_assert (counter == 1);
783+
784+}
785+
786+