summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>2011-01-17 16:35:48 +0100
committerGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>2011-05-12 12:30:41 +0200
commit15d953c08e40baa252e31b07d5c61565c841a3e3 (patch)
treeca68a3c2f2cbf5ec06f4238228ef967d5615292e
parent3d9c255172a9641fd7df32a71fbeeac0642ee08d (diff)
retry preparing failed dep, if possible
-rw-r--r--telepathy-glib/proxy.c37
-rw-r--r--tests/dbus/proxy-preparation.c40
-rw-r--r--tests/lib/my-conn-proxy.c31
-rw-r--r--tests/lib/my-conn-proxy.h5
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__ */