diff options
author | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2011-01-17 16:35:48 +0100 |
---|---|---|
committer | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2011-05-12 12:30:41 +0200 |
commit | 15d953c08e40baa252e31b07d5c61565c841a3e3 (patch) | |
tree | ca68a3c2f2cbf5ec06f4238228ef967d5615292e | |
parent | 3d9c255172a9641fd7df32a71fbeeac0642ee08d (diff) |
retry preparing failed dep, if possible
-rw-r--r-- | telepathy-glib/proxy.c | 37 | ||||
-rw-r--r-- | tests/dbus/proxy-preparation.c | 40 | ||||
-rw-r--r-- | tests/lib/my-conn-proxy.c | 31 | ||||
-rw-r--r-- | tests/lib/my-conn-proxy.h | 5 |
4 files changed, 105 insertions, 8 deletions
diff --git a/telepathy-glib/proxy.c b/telepathy-glib/proxy.c index f315abb7..28230d29 100644 --- a/telepathy-glib/proxy.c +++ b/telepathy-glib/proxy.c @@ -1627,12 +1627,16 @@ check_feature_interfaces (TpProxy *self, } /* Returns %TRUE if all the deps of @name are ready + * @can_retry: if %TRUE dependencies which have failed but have + * TpProxyFeature.can_retry won't be considered as having failed so we'll + * still have a change to retry preparing those. * @failed: (out): %TRUE if one of @name's dep can't be prepared and so * @name can't be either */ static gboolean check_depends_ready (TpProxy *self, GQuark name, + gboolean can_retry, gboolean *failed) { const TpProxyFeature *feature = tp_proxy_subclass_get_feature ( @@ -1649,21 +1653,35 @@ check_depends_ready (TpProxy *self, for (i = 0; feature->depends_on[i] != 0; i++) { GQuark dep = feature->depends_on[i]; + const TpProxyFeature *dep_feature = tp_proxy_subclass_get_feature ( + G_OBJECT_TYPE (self), dep); FeatureState dep_state; dep_state = tp_proxy_get_feature_state (self, dep); switch (dep_state) { case FEATURE_STATE_INVALID: - case FEATURE_STATE_FAILED: - DEBUG ("Can't prepare %s, one is dep %s: %s", - g_quark_to_string (name), - dep_state == FEATURE_STATE_INVALID ? "is invalid": "failed", - g_quark_to_string (dep)); + DEBUG ("Can't prepare %s, one dep is invalid: %s", + g_quark_to_string (name), g_quark_to_string (dep)); *failed = TRUE; return FALSE; + case FEATURE_STATE_FAILED: + if (!can_retry || !dep_feature->can_retry) + { + DEBUG ("Can't prepare %s, one dep failed: %s", + g_quark_to_string (name), g_quark_to_string (dep)); + + *failed = TRUE; + return FALSE; + } + + DEBUG ("retry preparing dep: %s", g_quark_to_string (dep)); + tp_proxy_set_feature_state (self, dep, FEATURE_STATE_WANTED); + ready = FALSE; + break; + case FEATURE_STATE_UNWANTED: case FEATURE_STATE_WANTED: case FEATURE_STATE_TRYING: @@ -1789,8 +1807,11 @@ tp_proxy_prepare_async (gpointer self, { gboolean failed; - /* Check deps */ - if (!check_depends_ready (self, features[i], &failed)) + /* Check deps. We only offer there the chance to retry a previously + * failed dependency. Doing it in tp_proxy_poll_features() could + * result in an infinite loop if we'd depends on 2 features which + * are constantly failing. */ + if (!check_depends_ready (self, features[i], TRUE, &failed)) { if (failed) { @@ -1962,7 +1983,7 @@ request_is_complete (TpProxy *self, continue; } - if (check_depends_ready (self, feature, &failed)) + if (check_depends_ready (self, feature, FALSE, &failed)) { /* We can prepare it now */ DEBUG ("%p: calling callback for %s", self, diff --git a/tests/dbus/proxy-preparation.c b/tests/dbus/proxy-preparation.c index fa9b088a..7b6f0d96 100644 --- a/tests/dbus/proxy-preparation.c +++ b/tests/dbus/proxy-preparation.c @@ -248,6 +248,44 @@ test_retry (Test *test, TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY)); } +static void +test_retry_dep (Test *test, + gconstpointer data G_GNUC_UNUSED) +{ + /* RETRY_DEP depends on a feature having can_retry and which failed, so + * preparing RETRY_DEP will re-prepare it successfully */ + GQuark features_retry[] = { TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY, 0 }; + GQuark features_retry_dep[] = { TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY_DEP, 0 }; + + /* Try preparing TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY, will fail */ + tp_proxy_prepare_async (test->my_conn, features_retry, prepare_cb, test); + + g_main_loop_run (test->mainloop); + g_assert_no_error (test->error); + + g_assert (tp_proxy_is_prepared (test->my_conn, + TP_TESTS_MY_CONN_PROXY_FEATURE_CORE)); + g_assert (!tp_proxy_is_prepared (test->my_conn, + TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY)); + g_assert (!tp_proxy_is_prepared (test->my_conn, + TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY_DEP)); + + /* Try prepare TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY_DEP, will re-prepare + * TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY */ + test->my_conn->retry_feature_success = TRUE; + tp_proxy_prepare_async (test->my_conn, features_retry_dep, prepare_cb, test); + + g_main_loop_run (test->mainloop); + g_assert_no_error (test->error); + + g_assert (tp_proxy_is_prepared (test->my_conn, + TP_TESTS_MY_CONN_PROXY_FEATURE_CORE)); + g_assert (tp_proxy_is_prepared (test->my_conn, + TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY)); + g_assert (tp_proxy_is_prepared (test->my_conn, + TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY_DEP)); +} + int main (int argc, char **argv) @@ -275,6 +313,8 @@ main (int argc, test_fail_dep, teardown); g_test_add ("/proxy-preparation/retry", Test, NULL, setup, test_retry, teardown); + g_test_add ("/proxy-preparation/retry-dep", Test, NULL, setup, + test_retry_dep, teardown); return g_test_run (); } diff --git a/tests/lib/my-conn-proxy.c b/tests/lib/my-conn-proxy.c index 26a32a83..765688b6 100644 --- a/tests/lib/my-conn-proxy.c +++ b/tests/lib/my-conn-proxy.c @@ -30,6 +30,7 @@ enum { FEAT_FAIL, FEAT_FAIL_DEP, FEAT_RETRY, + FEAT_RETRY_DEP, N_FEAT }; @@ -136,6 +137,23 @@ prepare_retry_async (TpProxy *proxy, g_object_unref (result); } +static void +prepare_retry_dep_async (TpProxy *proxy, + const TpProxyFeature *feature, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *result; + + g_assert (tp_proxy_is_prepared (proxy, TP_TESTS_MY_CONN_PROXY_FEATURE_CORE)); + + result = g_simple_async_result_new ((GObject *) proxy, callback, user_data, + prepare_retry_dep_async); + + g_simple_async_result_complete_in_idle (result); + g_object_unref (result); +} + static const TpProxyFeature * list_features (TpProxyClass *cls G_GNUC_UNUSED) { @@ -144,6 +162,7 @@ list_features (TpProxyClass *cls G_GNUC_UNUSED) static GQuark need_channel_core[2] = {0, 0}; static GQuark need_wrong_iface[2] = {0, 0}; static GQuark need_fail[2] = {0, 0}; + static GQuark need_retry[2] = {0, 0}; if (G_LIKELY (features[0].name != 0)) return features; @@ -186,6 +205,12 @@ list_features (TpProxyClass *cls G_GNUC_UNUSED) features[FEAT_RETRY].prepare_async = prepare_retry_async; features[FEAT_RETRY].can_retry = TRUE; + features[FEAT_RETRY_DEP].name = TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY_DEP; + if (G_UNLIKELY (need_retry[0] == 0)) + need_retry[0] = TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY; + features[FEAT_RETRY_DEP].prepare_async = prepare_retry_dep_async; + features[FEAT_RETRY_DEP].depends_on = need_retry; + return features; } @@ -244,3 +269,9 @@ tp_tests_my_conn_proxy_get_feature_quark_retry (void) { return g_quark_from_static_string ("tp-my-conn-proxy-feature-retry"); } + +GQuark +tp_tests_my_conn_proxy_get_feature_quark_retry_dep (void) +{ + return g_quark_from_static_string ("tp-my-conn-proxy-feature-retry-dep"); +} diff --git a/tests/lib/my-conn-proxy.h b/tests/lib/my-conn-proxy.h index 8dae142a..cc5505b9 100644 --- a/tests/lib/my-conn-proxy.h +++ b/tests/lib/my-conn-proxy.h @@ -90,6 +90,11 @@ GQuark tp_tests_my_conn_proxy_get_feature_quark_fail_dep (void) G_GNUC_CONST; (tp_tests_my_conn_proxy_get_feature_quark_retry ()) GQuark tp_tests_my_conn_proxy_get_feature_quark_retry (void) G_GNUC_CONST; +/* Depends on FEATURE_RETRY */ +#define TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY_DEP \ + (tp_tests_my_conn_proxy_get_feature_quark_retry_dep ()) +GQuark tp_tests_my_conn_proxy_get_feature_quark_retry_dep (void) G_GNUC_CONST; + G_END_DECLS #endif /* #ifndef __TP_TESTS_MY_CONN_PROXY_H__ */ |