3 #include "../engine/dconf-engine.h"
4 #include "../engine/dconf-engine-profile.h"
5 #include "dconf-mock.h"
7 #include <glib/gstdio.h>
14 /* Interpose to catch fopen("/etc/dconf/profile/user") */
15 static const gchar
*filename_to_replace
;
16 static const gchar
*filename_to_replace_it_with
;
19 fopen (const char *filename
,
22 static FILE * (*real_fopen
) (const char *, const char *);
25 real_fopen
= dlsym (RTLD_NEXT
, "fopen");
27 if (filename_to_replace
&& g_str_equal (filename
, filename_to_replace
))
29 /* Crash if this file was unexpectedly opened */
30 g_assert (filename_to_replace_it_with
!= NULL
);
31 filename
= filename_to_replace_it_with
;
34 return (* real_fopen
) (filename
, mode
);
37 static GThread
*main_thread
;
38 static GString
*change_log
;
41 dconf_engine_change_notify (DConfEngine
*engine
,
43 const gchar
* const *changes
,
49 g_string_append_printf (change_log
, "%s:%d:%s:%s;",
50 prefix
, g_strv_length ((gchar
**) changes
), changes
[0],
55 verify_and_free (DConfEngineSource
**sources
,
57 const gchar
* const *expected_names
,
62 g_assert_cmpint (n_sources
, ==, n_expected
);
64 g_assert ((sources
== NULL
) == (n_sources
== 0));
66 for (i
= 0; i
< n_sources
; i
++)
68 g_assert_cmpstr (sources
[i
]->name
, ==, expected_names
[i
]);
69 dconf_engine_source_free (sources
[i
]);
76 test_five_times (const gchar
*filename
,
80 const gchar
**expected_names
;
81 DConfEngineSource
**sources
;
86 expected_names
= g_new (const gchar
*, n_expected
);
87 va_start (ap
, n_expected
);
88 for (i
= 0; i
< n_expected
; i
++)
89 expected_names
[i
] = va_arg (ap
, const gchar
*);
92 /* first try by supplying the profile filename via the API */
93 g_assert (g_getenv ("DCONF_PROFILE") == NULL
);
94 g_assert (filename_to_replace
== NULL
);
95 sources
= dconf_engine_profile_open (filename
, &n_sources
);
96 verify_and_free (sources
, n_sources
, expected_names
, n_expected
);
98 /* next try supplying it via the environment */
99 g_setenv ("DCONF_PROFILE", filename
, TRUE
);
100 g_assert (filename_to_replace
== NULL
);
101 sources
= dconf_engine_profile_open (NULL
, &n_sources
);
102 verify_and_free (sources
, n_sources
, expected_names
, n_expected
);
103 g_unsetenv ("DCONF_PROFILE");
105 /* next try supplying a profile name via API and intercepting fopen */
106 filename_to_replace
= "/etc/dconf/profile/myprofile";
107 filename_to_replace_it_with
= filename
;
108 g_assert (g_getenv ("DCONF_PROFILE") == NULL
);
109 sources
= dconf_engine_profile_open ("myprofile", &n_sources
);
110 verify_and_free (sources
, n_sources
, expected_names
, n_expected
);
111 filename_to_replace
= NULL
;
113 /* next try the same, via the environment */
114 g_setenv ("DCONF_PROFILE", "myprofile", TRUE
);
115 filename_to_replace
= "/etc/dconf/profile/myprofile";
116 filename_to_replace_it_with
= filename
;
117 sources
= dconf_engine_profile_open (NULL
, &n_sources
);
118 verify_and_free (sources
, n_sources
, expected_names
, n_expected
);
119 g_unsetenv ("DCONF_PROFILE");
120 filename_to_replace
= NULL
;
122 /* next try to have dconf pick it up as the default user profile */
123 filename_to_replace
= "/etc/dconf/profile/user";
124 filename_to_replace_it_with
= filename
;
125 g_assert (g_getenv ("DCONF_PROFILE") == NULL
);
126 sources
= dconf_engine_profile_open (NULL
, &n_sources
);
127 verify_and_free (sources
, n_sources
, expected_names
, n_expected
);
128 filename_to_replace
= NULL
;
130 filename_to_replace_it_with
= NULL
;
131 g_free (expected_names
);
135 test_profile_parser (void)
137 DConfEngineSource
**sources
;
140 if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR
))
142 g_log_set_always_fatal (G_LOG_LEVEL_ERROR
);
144 sources
= dconf_engine_profile_open (SRCDIR
"/profile/this-file-does-not-exist", &n_sources
);
145 g_assert_cmpint (n_sources
, ==, 0);
146 g_assert (sources
== NULL
);
149 g_test_trap_assert_passed ();
150 g_test_trap_assert_stderr ("*WARNING*: unable to open named profile*");
152 if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR
))
154 g_log_set_always_fatal (G_LOG_LEVEL_ERROR
);
156 sources
= dconf_engine_profile_open (SRCDIR
"/profile/broken-profile", &n_sources
);
157 g_assert_cmpint (n_sources
, ==, 0);
158 g_assert (sources
== NULL
);
161 g_test_trap_assert_passed ();
162 g_test_trap_assert_stderr ("*WARNING*: unknown dconf database*unknown dconf database*");
164 if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR
))
166 g_log_set_always_fatal (G_LOG_LEVEL_ERROR
);
168 sources
= dconf_engine_profile_open (SRCDIR
"/profile/gdm", &n_sources
);
169 g_assert_cmpint (n_sources
, ==, 0);
170 g_assert (sources
== NULL
);
173 g_test_trap_assert_passed ();
174 g_test_trap_assert_stderr ("*WARNING*: unknown dconf database*unknown dconf database*");
176 test_five_times (SRCDIR
"/profile/empty-profile", 0);
177 test_five_times (SRCDIR
"/profile/test-profile", 1, "test");
178 test_five_times (SRCDIR
"/profile/colourful", 4,
181 "verylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongname",
183 test_five_times (SRCDIR
"/profile/dos", 2, "user", "site");
184 test_five_times (SRCDIR
"/profile/no-newline-longline", 0);
185 test_five_times (SRCDIR
"/profile/many-sources", 10,
186 "user", "local", "room", "floor", "building",
187 "site", "region", "division", "country", "global");
189 /* finally, test that we get the default profile if the user profile
190 * file cannot be located and we do not specify another profile.
192 filename_to_replace
= "/etc/dconf/profile/user";
193 filename_to_replace_it_with
= SRCDIR
"/profile/this-file-does-not-exist";
194 g_assert (g_getenv ("DCONF_PROFILE") == NULL
);
195 sources
= dconf_engine_profile_open (NULL
, &n_sources
);
196 filename_to_replace
= NULL
;
197 g_assert_cmpint (n_sources
, ==, 1);
198 g_assert_cmpstr (sources
[0]->name
, ==, "user");
199 dconf_engine_source_free (sources
[0]);
202 dconf_mock_shm_reset ();
206 test_signal_threadsafety_worker (gpointer user_data
)
208 gint
*finished
= user_data
;
211 for (i
= 0; i
< 20000; i
++)
215 engine
= dconf_engine_new (NULL
, NULL
);
216 dconf_engine_unref (engine
);
219 g_atomic_int_inc (finished
);
225 test_signal_threadsafety (void)
228 GVariant
*parameters
;
232 parameters
= g_variant_new_parsed ("('/test/key', [''], 'tag')");
233 g_variant_ref_sink (parameters
);
235 for (i
= 0; i
< N_WORKERS
; i
++)
236 g_thread_unref (g_thread_new ("testcase worker", test_signal_threadsafety_worker
, &finished
));
238 while (g_atomic_int_get (&finished
) < N_WORKERS
)
239 dconf_engine_handle_dbus_signal (G_BUS_TYPE_SESSION
,
241 "/ca/desrt/dconf/Writer/user",
242 "Notify", parameters
);
243 g_variant_unref (parameters
);
245 dconf_mock_shm_reset ();
249 test_user_source (void)
251 DConfEngineSource
*source
;
256 /* Create the source from a clean slate */
257 source
= dconf_engine_source_new ("user-db:user");
258 g_assert (source
!= NULL
);
259 g_assert (source
->values
== NULL
);
260 g_assert (source
->locks
== NULL
);
262 /* Refresh it the first time.
263 * This should cause it to open the shm.
264 * FALSE should be returned because there is no database file.
266 reopened
= dconf_engine_source_refresh (source
);
267 g_assert (!reopened
);
268 dconf_mock_shm_assert_log ("open user;");
270 /* Try to refresh it. There must be no IO at this point. */
271 reopened
= dconf_engine_source_refresh (source
);
272 g_assert (!reopened
);
273 dconf_mock_shm_assert_log ("");
275 /* Add a real database. */
276 table
= dconf_mock_gvdb_table_new ();
277 dconf_mock_gvdb_table_insert (table
, "/values/int32", g_variant_new_int32 (123456), NULL
);
278 dconf_mock_gvdb_install ("/HOME/.config/dconf/user", table
);
280 /* Try to refresh it again.
281 * Because we didn't flag the change there must still be no IO.
283 reopened
= dconf_engine_source_refresh (source
);
284 g_assert (!reopened
);
285 g_assert (source
->values
== NULL
);
286 g_assert (source
->locks
== NULL
);
287 dconf_mock_shm_assert_log ("");
289 /* Now flag it and reopen. */
290 dconf_mock_shm_flag ("user");
291 reopened
= dconf_engine_source_refresh (source
);
293 g_assert (source
->values
!= NULL
);
294 g_assert (source
->locks
== NULL
);
295 g_assert (gvdb_table_has_value (source
->values
, "/values/int32"));
296 dconf_mock_shm_assert_log ("close;open user;");
298 /* Do it again -- should get the same result, after some IO */
299 dconf_mock_shm_flag ("user");
300 reopened
= dconf_engine_source_refresh (source
);
302 g_assert (source
->values
!= NULL
);
303 g_assert (source
->locks
== NULL
);
304 dconf_mock_shm_assert_log ("close;open user;");
306 /* "Delete" the gvdb and make sure dconf notices after a flag */
307 dconf_mock_gvdb_install ("/HOME/.config/dconf/user", NULL
);
308 dconf_mock_shm_flag ("user");
309 reopened
= dconf_engine_source_refresh (source
);
311 g_assert (source
->values
== NULL
);
312 g_assert (source
->locks
== NULL
);
313 dconf_mock_shm_assert_log ("close;open user;");
315 /* Add a gvdb with a lock */
316 table
= dconf_mock_gvdb_table_new ();
317 locks
= dconf_mock_gvdb_table_new ();
318 dconf_mock_gvdb_table_insert (table
, "/values/int32", g_variant_new_int32 (123456), NULL
);
319 dconf_mock_gvdb_table_insert (locks
, "/values/int32", g_variant_new_boolean (TRUE
), NULL
);
320 dconf_mock_gvdb_table_insert (table
, ".locks", NULL
, locks
);
321 dconf_mock_gvdb_install ("/HOME/.config/dconf/user", table
);
323 /* Reopen and check if we have the lock */
324 dconf_mock_shm_flag ("user");
325 reopened
= dconf_engine_source_refresh (source
);
327 g_assert (source
->values
!= NULL
);
328 g_assert (source
->locks
!= NULL
);
329 g_assert (gvdb_table_has_value (source
->values
, "/values/int32"));
330 g_assert (gvdb_table_has_value (source
->locks
, "/values/int32"));
331 dconf_mock_shm_assert_log ("close;open user;");
333 /* Reopen one last time */
334 dconf_mock_shm_flag ("user");
335 reopened
= dconf_engine_source_refresh (source
);
337 g_assert (source
->values
!= NULL
);
338 g_assert (source
->locks
!= NULL
);
339 dconf_mock_shm_assert_log ("close;open user;");
341 dconf_engine_source_free (source
);
342 dconf_mock_shm_assert_log ("close;");
344 dconf_mock_gvdb_install ("/HOME/.config/dconf/user", NULL
);
345 dconf_mock_shm_reset ();
349 test_system_source (void)
351 DConfEngineSource
*source
;
352 GvdbTable
*first_table
;
353 GvdbTable
*next_table
;
356 source
= dconf_engine_source_new ("system-db:site");
357 g_assert (source
!= NULL
);
359 /* Check to see that we get the warning about the missing file. */
360 if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR
))
362 g_log_set_always_fatal (G_LOG_LEVEL_ERROR
);
364 /* Failing to open should return FALSE from refresh */
365 reopened
= dconf_engine_source_refresh (source
);
366 g_assert (!reopened
);
367 g_assert (source
->values
== NULL
);
369 /* Attempt the reopen to make sure we don't get two warnings.
370 * We should see FALSE again since we go from NULL to NULL.
372 reopened
= dconf_engine_source_refresh (source
);
373 g_assert (!reopened
);
375 /* Create the file after the fact and make sure it opens properly */
376 first_table
= dconf_mock_gvdb_table_new ();
377 dconf_mock_gvdb_install ("/etc/dconf/db/site", first_table
);
379 reopened
= dconf_engine_source_refresh (source
);
381 g_assert (source
->values
!= NULL
);
383 dconf_engine_source_free (source
);
387 g_test_trap_assert_passed ();
388 /* Check that we only saw the warning, but only one time. */
389 g_test_trap_assert_stderr ("*this gvdb does not exist; expect degraded performance*");
390 g_test_trap_assert_stderr_unmatched ("*degraded*degraded*");
392 /* Create the file before the first refresh attempt */
393 first_table
= dconf_mock_gvdb_table_new ();
394 dconf_mock_gvdb_install ("/etc/dconf/db/site", first_table
);
395 /* Hang on to a copy for ourselves for below... */
396 dconf_mock_gvdb_table_ref (first_table
);
398 /* See that we get the database. */
399 reopened
= dconf_engine_source_refresh (source
);
401 g_assert (source
->values
== first_table
);
403 /* Do a refresh, make sure there is no change. */
404 reopened
= dconf_engine_source_refresh (source
);
405 g_assert (!reopened
);
406 g_assert (source
->values
== first_table
);
408 /* Replace the table on "disk" but don't invalidate the old one */
409 next_table
= dconf_mock_gvdb_table_new ();
410 dconf_mock_gvdb_install ("/etc/dconf/db/site", next_table
);
412 /* Make sure the old table remains open (ie: no IO performed) */
413 reopened
= dconf_engine_source_refresh (source
);
414 g_assert (!reopened
);
415 g_assert (source
->values
== first_table
);
417 /* Now mark the first table invalid and reopen */
418 dconf_mock_gvdb_table_invalidate (first_table
);
419 gvdb_table_free (first_table
);
420 reopened
= dconf_engine_source_refresh (source
);
422 g_assert (source
->values
== next_table
);
424 /* Remove the file entirely and do the same thing */
425 dconf_mock_gvdb_install ("/etc/dconf/db/site", NULL
);
426 reopened
= dconf_engine_source_refresh (source
);
427 g_assert (!reopened
);
429 dconf_engine_source_free (source
);
433 invalidate_state (guint n_sources
,
439 for (i
= 0; i
< n_sources
; i
++)
440 if (source_types
& (1u << i
))
444 dconf_mock_gvdb_table_invalidate (state
[i
]);
445 gvdb_table_free (state
[i
]);
450 dconf_mock_shm_flag (state
[i
]);
456 setup_state (guint n_sources
,
458 guint database_state
,
463 for (i
= 0; i
< n_sources
; i
++)
465 guint contents
= database_state
% 7;
466 GvdbTable
*table
= NULL
;
471 table
= dconf_mock_gvdb_table_new ();
473 /* Even numbers get the value setup */
474 if ((contents
& 1) == 0)
475 dconf_mock_gvdb_table_insert (table
, "/value", g_variant_new_uint32 (i
), NULL
);
477 /* Numbers above 2 get the locks table */
482 locks
= dconf_mock_gvdb_table_new ();
484 /* Numbers above 4 get the lock set */
486 dconf_mock_gvdb_table_insert (locks
, "/value", g_variant_new_boolean (TRUE
), NULL
);
488 dconf_mock_gvdb_table_insert (table
, ".locks", NULL
, locks
);
492 if (source_types
& (1u << i
))
497 state
[i
] = dconf_mock_gvdb_table_ref (table
);
502 filename
= g_strdup_printf ("/etc/dconf/db/db%d", i
);
507 state
[i
] = g_strdup_printf ("db%d", i
);
509 filename
= g_strdup_printf ("/HOME/.config/dconf/db%d", i
);
512 dconf_mock_gvdb_install (filename
, table
);
520 create_profile (const gchar
*filename
,
524 GError
*error
= NULL
;
528 profile
= g_string_new (NULL
);
529 for (i
= 0; i
< n_sources
; i
++)
530 if (source_types
& (1u << i
))
531 g_string_append_printf (profile
, "system-db:db%d\n", i
);
533 g_string_append_printf (profile
, "user-db:db%d\n", i
);
534 g_file_set_contents (filename
, profile
->str
, profile
->len
, &error
);
535 g_assert_no_error (error
);
536 g_string_free (profile
, TRUE
);
540 check_read (DConfEngine
*engine
,
543 guint database_state
)
545 gboolean any_values
= FALSE
;
546 gboolean any_locks
= FALSE
;
553 /* The value we expect to read is number of the first source that has
554 * the value set (ie: odd digit in database_state) up to the lowest
557 * We go over each database. If 'expected' has not yet been set and
558 * we find that we should have a value in this database, we set it.
559 * If we find that we should have a lock in this database, we unset
560 * any previous values (since they should not have been written).
562 * We initially code this loop in a different way than the one in
563 * dconf itself is currently implemented...
565 * We also take note of if we saw any locks and cross-check that with
566 * dconf_engine_is_writable(). We check if we saw and values at all
567 * and cross-check that with dconf_engine_list() (which ignores
570 for (i
= 0; i
< n_sources
; i
++)
572 guint contents
= database_state
% 7;
574 /* A lock here should prevent higher reads */
577 /* Locks in the first database don't count... */
583 /* A value here should be read */
584 if (contents
&& !(contents
& 1) && expected
== -1)
593 value
= dconf_engine_read (engine
, NULL
, "/value");
597 g_assert (g_variant_is_of_type (value
, G_VARIANT_TYPE_UINT32
));
598 g_assert_cmpint (g_variant_get_uint32 (value
), ==, expected
);
599 g_variant_unref (value
);
602 g_assert (value
== NULL
);
604 /* We are writable if the first database is a user database and we
605 * didn't encounter any locks...
607 writable
= dconf_engine_is_writable (engine
, "/value");
608 g_assert_cmpint (writable
, ==, n_sources
&& !(source_types
& 1) && !any_locks
);
610 list
= dconf_engine_list (engine
, "/", NULL
);
613 g_assert_cmpstr (list
[0], ==, "value");
614 g_assert (list
[1] == NULL
);
617 g_assert (list
[0] == NULL
);
624 #define MAX_N_SOURCES 3
625 gpointer state
[MAX_N_SOURCES
];
626 gchar
*profile_filename
;
627 GError
*error
= NULL
;
632 /* Hack to silence warning */
633 if (!g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR
))
635 g_test_trap_assert_passed ();
636 g_test_trap_assert_stderr ("*this gvdb does not exist; expect degraded performance*");
639 g_log_set_always_fatal (G_LOG_LEVEL_ERROR
);
641 /* Our test strategy is as follows:
643 * We only test a single key name. It is assumed that gvdb is working
644 * properly already so we are only interested in interactions between
645 * multiple databases for a given key name.
647 * The outermost loop is over 'n'. This is how many sources are in
648 * our test. We test 0 to 3 (which should be enough to cover all
649 * 'interesting' possibilities). 4 takes too long to run (2*7*7 ~=
650 * 100 times as long as 3).
652 * The next loop is over 'i'. This goes from 0 to 2^n - 1, with each
653 * bit deciding the type of source of the i-th element
659 * The next loop is over 'j'. This goes from 0 to 7^n - 1, with each
660 * base-7 digit deciding the state of the database file associated
661 * with the i-th source:
663 * j file has value has ".locks" has lock
664 * ----------------------------------------------------
673 * Where 'file' is if the database file exists, 'has value' is if a
674 * value exists at '/value' within the file, 'has ".locks"' is if
675 * there is a ".locks" subtable and 'has lock' is if there is a lock
676 * for '/value' within that table.
678 * Finally, we loop over 'k' as a state to transition to ('k' works
679 * the same way as 'j').
681 * Once we know 'n' and 'i', we can write a profile file.
683 * Once we know 'j' we can setup the initial state, create the engine
684 * and check that we got the expected value. Then we transition to
685 * state 'k' and make sure everything still works as expected.
687 * Since we want to test all j->k transitions, we do the initial setup
688 * of the engine (according to j) inside of the 'k' loop, since we
689 * need to test all possible transitions from 'j'.
692 /* We need a place to put the profile files we use for this test */
693 close (g_file_open_tmp ("dconf-testcase.XXXXXX", &profile_filename
, &error
));
694 g_assert_no_error (error
);
696 g_setenv ("DCONF_PROFILE", profile_filename
, TRUE
);
698 for (n
= 0; n
< MAX_N_SOURCES
; n
++)
699 for (i
= 0; i
< pow (2, n
); i
++)
701 gint n_possible_states
= pow (7, n
);
703 /* Step 1: write out the profile file */
704 create_profile (profile_filename
, n
, i
);
706 for (j
= 0; j
< n_possible_states
; j
++)
707 for (k
= 0; k
< n_possible_states
; k
++)
709 guint64 old_state
, new_state
;
711 /* Step 2: setup the state */
712 setup_state (n
, i
, j
, (j
!= k
) ? state
: NULL
);
714 /* Step 3: create the engine */
715 engine
= dconf_engine_new (NULL
, NULL
);
717 /* Step 4: read, and check result */
718 check_read (engine
, n
, i
, j
);
719 old_state
= dconf_engine_get_state (engine
);
721 /* Step 5: change to the new state */
724 setup_state (n
, i
, k
, NULL
);
725 invalidate_state (n
, i
, state
);
728 /* Step 6: read, and check result */
729 check_read (engine
, n
, i
, k
);
730 new_state
= dconf_engine_get_state (engine
);
732 g_assert ((j
== k
) == (new_state
== old_state
));
735 setup_state (n
, i
, 0, NULL
);
736 dconf_engine_unref (engine
);
740 /* Clean up the tempfile we were using... */
741 g_unsetenv ("DCONF_PROFILE");
742 g_unlink (profile_filename
);
743 g_free (profile_filename
);
748 test_watch_fast (void)
755 change_log
= g_string_new (NULL
);
757 table
= dconf_mock_gvdb_table_new ();
758 dconf_mock_gvdb_install ("/HOME/.config/dconf/user", table
);
759 table
= dconf_mock_gvdb_table_new ();
760 dconf_mock_gvdb_install ("/etc/dconf/db/site", table
);
762 triv
= g_variant_ref_sink (g_variant_new ("()"));
764 g_setenv ("DCONF_PROFILE", SRCDIR
"/profile/dos", TRUE
);
765 engine
= dconf_engine_new (NULL
, NULL
);
766 g_unsetenv ("DCONF_PROFILE");
768 /* Check that establishing a watch works properly in the normal case.
770 a
= dconf_engine_get_state (engine
);
771 dconf_engine_watch_fast (engine
, "/a/b/c");
772 /* watches do not count as outstanding changes */
773 g_assert (!dconf_engine_has_outstanding (engine
));
774 dconf_engine_sync (engine
);
775 b
= dconf_engine_get_state (engine
);
776 g_assert_cmpuint (a
, ==, b
);
777 /* both AddMatch results come back before shm is flagged */
778 dconf_engine_call_handle_reply (g_queue_pop_head (&dconf_mock_dbus_outstanding_call_handles
), triv
, NULL
);
779 dconf_engine_call_handle_reply (g_queue_pop_head (&dconf_mock_dbus_outstanding_call_handles
), triv
, NULL
);
780 g_assert (g_queue_is_empty (&dconf_mock_dbus_outstanding_call_handles
));
781 dconf_mock_shm_flag ("user");
782 b
= dconf_engine_get_state (engine
);
783 g_assert_cmpuint (a
, !=, b
);
784 g_assert_cmpstr (change_log
->str
, ==, "");
785 dconf_engine_unwatch_fast (engine
, "/a/b/c");
786 dconf_engine_call_handle_reply (g_queue_pop_head (&dconf_mock_dbus_outstanding_call_handles
), triv
, NULL
);
787 dconf_engine_call_handle_reply (g_queue_pop_head (&dconf_mock_dbus_outstanding_call_handles
), triv
, NULL
);
788 g_assert (g_queue_is_empty (&dconf_mock_dbus_outstanding_call_handles
));
790 /* Establish a watch and fail the race. */
791 a
= dconf_engine_get_state (engine
);
792 dconf_engine_watch_fast (engine
, "/a/b/c");
793 g_assert (!dconf_engine_has_outstanding (engine
));
794 dconf_engine_sync (engine
);
795 b
= dconf_engine_get_state (engine
);
796 g_assert_cmpuint (a
, ==, b
);
797 /* one AddMatch result comes back -after- shm is flagged */
798 dconf_engine_call_handle_reply (g_queue_pop_head (&dconf_mock_dbus_outstanding_call_handles
), triv
, NULL
);
799 dconf_mock_shm_flag ("user");
800 dconf_engine_call_handle_reply (g_queue_pop_head (&dconf_mock_dbus_outstanding_call_handles
), triv
, NULL
);
801 g_assert (g_queue_is_empty (&dconf_mock_dbus_outstanding_call_handles
));
802 b
= dconf_engine_get_state (engine
);
803 g_assert_cmpuint (a
, !=, b
);
804 g_assert_cmpstr (change_log
->str
, ==, "/:1::nil;");
805 dconf_engine_unwatch_fast (engine
, "/a/b/c");
806 dconf_engine_call_handle_reply (g_queue_pop_head (&dconf_mock_dbus_outstanding_call_handles
), triv
, NULL
);
807 dconf_engine_call_handle_reply (g_queue_pop_head (&dconf_mock_dbus_outstanding_call_handles
), triv
, NULL
);
808 g_assert (g_queue_is_empty (&dconf_mock_dbus_outstanding_call_handles
));
810 dconf_mock_gvdb_install ("/HOME/.config/dconf/user", NULL
);
811 dconf_mock_gvdb_install ("/etc/dconf/db/site", NULL
);
812 dconf_engine_unref (engine
);
813 g_string_free (change_log
, TRUE
);
815 g_variant_unref (triv
);
818 static const gchar
*match_request_type
;
819 static gboolean got_match_request
[5];
822 handle_match_request (GBusType bus_type
,
823 const gchar
*bus_name
,
824 const gchar
*object_path
,
825 const gchar
*interface_name
,
826 const gchar
*method_name
,
827 GVariant
*parameters
,
828 const GVariantType
*expected_type
,
831 const gchar
*match_rule
;
833 g_assert_cmpstr (bus_name
, ==, "org.freedesktop.DBus");
834 /* any object path works... */
835 g_assert_cmpstr (bus_name
, ==, "org.freedesktop.DBus");
836 g_assert_cmpstr (method_name
, ==, match_request_type
);
837 g_assert_cmpstr (g_variant_get_type_string (parameters
), ==, "(s)");
838 g_variant_get (parameters
, "(&s)", &match_rule
);
839 g_assert (strstr (match_rule
, "arg0path='/a/b/c'"));
840 g_assert (!got_match_request
[bus_type
]);
841 got_match_request
[bus_type
] = TRUE
;
843 return g_variant_new ("()");
847 test_watch_sync (void)
851 dconf_mock_dbus_sync_call_handler
= handle_match_request
;
853 g_setenv ("DCONF_PROFILE", SRCDIR
"/profile/dos", TRUE
);
854 engine
= dconf_engine_new (NULL
, NULL
);
855 g_unsetenv ("DCONF_PROFILE");
857 match_request_type
= "AddMatch";
858 dconf_engine_watch_sync (engine
, "/a/b/c");
859 g_assert (got_match_request
[G_BUS_TYPE_SESSION
]);
860 g_assert (got_match_request
[G_BUS_TYPE_SYSTEM
]);
861 got_match_request
[G_BUS_TYPE_SESSION
] = FALSE
;
862 got_match_request
[G_BUS_TYPE_SYSTEM
] = FALSE
;
864 match_request_type
= "RemoveMatch";
865 dconf_engine_unwatch_sync (engine
, "/a/b/c");
866 g_assert (got_match_request
[G_BUS_TYPE_SESSION
]);
867 g_assert (got_match_request
[G_BUS_TYPE_SYSTEM
]);
868 got_match_request
[G_BUS_TYPE_SESSION
] = FALSE
;
869 got_match_request
[G_BUS_TYPE_SYSTEM
] = FALSE
;
871 dconf_engine_unref (engine
);
873 dconf_mock_dbus_sync_call_handler
= NULL
;
874 match_request_type
= NULL
;
878 main (int argc
, char **argv
)
880 g_setenv ("XDG_CONFIG_HOME", "/HOME/.config", TRUE
);
881 g_unsetenv ("DCONF_PROFILE");
883 main_thread
= g_thread_self ();
885 g_test_init (&argc
, &argv
, NULL
);
887 g_test_add_func ("/engine/profile-parser", test_profile_parser
);
888 g_test_add_func ("/engine/signal-threadsafety", test_signal_threadsafety
);
889 g_test_add_func ("/engine/sources/user", test_user_source
);
890 g_test_add_func ("/engine/sources/system", test_system_source
);
891 g_test_add_func ("/engine/read", test_read
);
892 g_test_add_func ("/engine/watch/fast", test_watch_fast
);
893 g_test_add_func ("/engine/watch/sync", test_watch_sync
);
895 return g_test_run ();