@@ -138,6 +138,69 @@ class FirebaseTest : public testing::Test {
138138 static bool WaitForCompletion (const firebase::FutureBase& future,
139139 const char * name, int expected_error = 0 );
140140
141+ // Run an operation that returns a Future (via a callback), retrying with
142+ // exponential backoff if the operation fails.
143+ //
144+ // Blocks until the operation succeeds (the Future completes, with error
145+ // matching expected_error) or if the final attempt is started (in which case
146+ // the Future returned may still be in progress). You should use
147+ // WaitForCompletion to await the results of this function in any case.
148+ //
149+ // For example, to add retry, you would change:
150+ //
151+ // bool success = WaitForCompletion(
152+ // auth_->DeleteUser(auth->current_user()),
153+ // "DeleteUser");
154+ // To this:
155+ //
156+ // bool success = WaitForCompletion(RunWithRetry(
157+ // [](Auth* auth) {
158+ // return auth->DeleteUser(auth->current_user());
159+ // }, auth_), "DeleteUser"));
160+ template <class CallbackType , class ContextType >
161+ static firebase::FutureBase RunWithRetry (
162+ CallbackType run_future_typed,
163+ ContextType* context_typed,
164+ const char * name = " " ,
165+ int expected_error = 0 ) {
166+ struct RunData { CallbackType callback; ContextType* context; };
167+ RunData run_data = { run_future_typed, context_typed };
168+ return RunWithRetryBase (
169+ [](void *ctx) {
170+ CallbackType callback = static_cast <RunData*>(ctx)->callback ;
171+ ContextType* context = static_cast <RunData*>(ctx)->context ;
172+ return static_cast <firebase::FutureBase>(callback (context));
173+ },
174+ static_cast <void *>(&run_data),name, expected_error);
175+ }
176+
177+ // Same as RunWithRetry, but templated to return a Future<ResultType>
178+ // rather than a FutureBase, in case you want to use the result data
179+ // of the Future. You need to explicitly provide the template parameter,
180+ // e.g. RunWithRetry<int>(..) to return a Future<int>.
181+ template <class ResultType , class CallbackType , class ContextType >
182+ static firebase::Future<ResultType> RunWithRetry (
183+ CallbackType run_future_typed,
184+ ContextType* context_typed,
185+ const char * name = " " ,
186+ int expected_error = 0 ) {
187+ struct RunData { CallbackType callback; ContextType* context; };
188+ RunData run_data = { run_future_typed, context_typed };
189+ firebase::FutureBase result_base = RunWithRetryBase (
190+ [](void *ctx) {
191+ CallbackType callback = static_cast <RunData*>(ctx)->callback ;
192+ ContextType* context = static_cast <RunData*>(ctx)->context ;
193+ // The following line checks that CallbackType actually returns a
194+ // Future<ResultType>. If it returns any other type, the compiler will
195+ // complain about implicit conversion to Future<ResultType> here.
196+ firebase::Future<ResultType> future_result = callback (context);
197+ return static_cast <firebase::FutureBase>(future_result);
198+ },
199+ static_cast <void *>(&run_data),name, expected_error);
200+ // Future<T> and FutureBase are reinterpret_cast-compatible, by design.
201+ return *reinterpret_cast <firebase::Future<ResultType>*>(&result_base);
202+ }
203+
141204 // Blocking HTTP request helper function, for testing only.
142205 static bool SendHttpGetRequest (
143206 const char * url, const std::map<std::string, std::string>& headers,
@@ -161,10 +224,20 @@ class FirebaseTest : public testing::Test {
161224 // false if it failed.
162225 static bool Base64Decode (const std::string& input, std::string* output);
163226
227+
164228 firebase::App* app_;
165229 static int argc_;
166230 static char ** argv_;
167231 static bool found_config_;
232+
233+ private:
234+ // Untyped version of RunWithRetry, with implementation.
235+ // This is kept private because the templated version should be used instead,
236+ // for type safety.
237+ static firebase::FutureBase RunWithRetryBase (
238+ firebase::FutureBase (*run_future)(void * context),
239+ void* context,
240+ const char* name, int expected_error);
168241};
169242
170243} // namespace firebase_test_framework
0 commit comments