* Bug 666540 — Segfault on empty e-mail addresses with potential match
* Bug 659610 — Support code coverage report generation
* Bug 657063 — Allow to pass a command to folks-inspect
+* Bug 667410 — A second instance of the aggregator only fetch a small subset of
+ my contacts
API changes:
* Add PostalAddress.is_empty() and Role.is_empty()
*/
public abstract class Folks.Backend : Object
{
+ construct
+ {
+ debug ("Constructing Backend ‘%s’ (%p)", this.name, this);
+ }
+
+ ~Backend ()
+ {
+ debug ("Destroying Backend ‘%s’ (%p)", this.name, this);
+ }
+
/**
* Whether {@link Backend.prepare} has successfully completed for this
* backend.
disable_linking == "no" || disable_linking == "0");
this._backend_store = BackendStore.dup ();
- this._backend_store.backend_available.connect (
- this._backend_available_cb);
+
+ debug ("Constructing IndividualAggregator %p", this);
}
~IndividualAggregator ()
{
+ debug ("Destroying IndividualAggregator %p", this);
+
this._backend_store.backend_available.disconnect (
this._backend_available_cb);
{
this._prepare_pending = true;
+ this._backend_store.backend_available.connect (
+ this._backend_available_cb);
+
+ /* Load any backends which already exist. This could happen if the
+ * BackendStore has stayed alive after being used by a previous
+ * IndividualAggregator instance. */
+ var backends = this._backend_store.enabled_backends.values;
+ foreach (var backend in backends)
+ {
+ this._backend_available_cb (this._backend_store, backend);
+ }
+
+ /* Load any backends which haven't been loaded already. (Typically
+ * all of them.) */
yield this._backend_store.load_backends ();
this._is_prepared = true;
this.notify_property ("is-prepared");
+
+ /* Mark the aggregator as having reached a quiescent state if
+ * appropriate. This will typically only happen here in cases
+ * where the stores were all prepared and quiescent before the
+ * aggregator was created. */
+ if (this._is_quiescent == false)
+ {
+ this._notify_if_is_quiescent ();
+ }
}
finally
{
private void _backend_persona_store_added_cb (Backend backend,
PersonaStore store)
{
+ debug ("_backend_persona_store_added_cb(): backend: %s, store: %s (%p)",
+ backend.name, store.id, store);
+
var store_id = this._get_store_full_id (store.type_id, store.id);
this._maybe_configure_as_primary (store);
this._non_quiescent_persona_store_count++;
}
+ /* Handle any pre-existing personas in the store. This can happen if the
+ * store existed (and was prepared) before this IndividualAggregator was
+ * constructed. */
+ if (store.personas.size > 0)
+ {
+ var persona_set = new HashSet<Persona> ();
+ foreach (var p in store.personas.values)
+ {
+ persona_set.add (p);
+ }
+
+ this._personas_changed_cb (store, persona_set,
+ new HashSet<Persona> (), null, null,
+ GroupDetails.ChangeReason.NONE);
+ }
+
+ /* Prepare the store and receive a load of other personas-changed
+ * signals. */
store.prepare.begin ((obj, result) =>
{
try
*/
public abstract class Folks.PersonaStore : Object
{
+ construct
+ {
+ debug ("Constructing PersonaStore ‘%s’ (%p)", this.id, this);
+ }
+
+ ~PersonaStore ()
+ {
+ debug ("Destroying PersonaStore ‘%s’ (%p)", this.id, this);
+ }
+
/**
* The following list of properties are the basic keys
* that each PersonaStore with write capabilities should
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+ * Philip Withnall <philip@tecnocode.co.uk>
*/
using Gee;
/* Set up the tests */
this.add_test ("looped", this.test_looped);
+ this.add_test ("individual-count", this.test_individual_count);
}
public override void set_up ()
this._tp_backend.remove_account (account1_handle);
this._kf_backend.tear_down ();
}
+
+ /* Prepare an aggregator and wait for quiescence, then count how many
+ * individuals it contains. Loop and do the same thing again, then compare
+ * the numbers of individuals and their IDs. Do this several times.
+ *
+ * This tests that the preparation code in IndividualAggregator can handle
+ * Backends and PersonaStores which have been prepared before the aggregator
+ * was created. To a lesser extent, it also tests that the aggregation code
+ * is deterministic. See: bgo#667410. */
+ public void test_individual_count ()
+ {
+ var main_loop = new GLib.MainLoop (null, false);
+
+ this._kf_backend.set_up (
+ "[0]\n" +
+ "msn=foo@hotmail.com\n" +
+ "[1]\n" +
+ "__alias=Bar McBadgerson\n" +
+ "jabber=bar@jabber.org\n");
+
+ void* account1_handle = this._tp_backend.add_account ("protocol",
+ "me@example.com", "cm", "account");
+ void* account2_handle = this._tp_backend.add_account ("protocol",
+ "me2@example.com", "cm", "account2");
+
+ /* Run the test loop. */
+ Idle.add (() =>
+ {
+ this._test_individual_count_loop.begin ((obj, res) =>
+ {
+ this._test_individual_count_loop.end (res);
+ main_loop.quit ();
+ });
+
+ return false;
+ });
+
+ main_loop.run ();
+
+ /* Clean up for the next test */
+ this._tp_backend.remove_account (account2_handle);
+ this._tp_backend.remove_account (account1_handle);
+
+ this._kf_backend.tear_down ();
+ }
+
+ private async void _test_individual_count_loop ()
+ {
+ string[]? previous_individual_ids = null;
+
+ for (uint i = 0; i < 10; i++)
+ {
+ var aggregator = new IndividualAggregator ();
+
+ try
+ {
+ yield TestUtils.aggregator_prepare_and_wait_for_quiescence (
+ aggregator);
+ }
+ catch (GLib.Error e1)
+ {
+ GLib.critical ("Error preparing aggregator: %s", e1.message);
+ }
+
+ if (previous_individual_ids == null)
+ {
+ /* First iteration; store the set of IDs. */
+ previous_individual_ids = aggregator.individuals.keys.to_array ();
+ }
+ else
+ {
+ /* Compare this set to the previous aggregator's set. */
+ debug ("%u vs %u individuals:", previous_individual_ids.length,
+ aggregator.individuals.size);
+ assert (previous_individual_ids.length ==
+ aggregator.individuals.size);
+ assert (aggregator.individuals.size > 0);
+
+ foreach (var id in previous_individual_ids)
+ {
+ debug (" %s", id);
+ assert (aggregator.individuals.has_key (id) == true);
+ }
+ }
+
+ /* Destroy the aggregator and loop. */
+ aggregator = null;
+ }
+ }
}
public int main (string[] args)