52
62
g_assert (_test_success == TRUE); \
65
/* Common code for tests of async query functions that have progress callbacks */
67
guint progress_destroy_notify_count;
68
guint async_ready_notify_count;
70
} GDataAsyncProgressClosure;
71
void gdata_test_async_progress_callback (GDataEntry *entry, guint entry_key, guint entry_count, GDataAsyncProgressClosure *data);
72
void gdata_test_async_progress_closure_free (GDataAsyncProgressClosure *data);
73
void gdata_test_async_progress_finish_callback (GObject *service, GAsyncResult *res, GDataAsyncProgressClosure *data);
78
GCancellable *cancellable;
79
guint cancellation_timeout; /* timeout period in ms */
80
guint cancellation_timeout_id; /* ID of the callback source */
81
gboolean cancellation_successful;
83
gconstpointer test_data;
87
* GDATA_ASYNC_CLOSURE_FUNCTIONS:
88
* @CLOSURE_NAME: the name of the closure
89
* @TestStructType: the type of the synchronous closure structure
91
* Defines set up and tear down functions for a version of @TestStructType which is wrapped by #GDataAsyncTestData (i.e. allocated and pointed to by
92
* the #GDataAsyncTestData.test_data pointer). These functions will be named <function>set_up_<replaceable>CLOSURE_NAME</replaceable>_async</function>
93
* and <function>tear_down_<replaceable>CLOSURE_NAME</replaceable>_async</function>.
97
#define GDATA_ASYNC_CLOSURE_FUNCTIONS(CLOSURE_NAME, TestStructType) \
99
set_up_##CLOSURE_NAME##_async (GDataAsyncTestData *async_data, gconstpointer service) \
101
TestStructType *test_data = g_slice_new (TestStructType); \
102
set_up_##CLOSURE_NAME (test_data, service); \
103
gdata_set_up_async_test_data (async_data, test_data); \
107
tear_down_##CLOSURE_NAME##_async (GDataAsyncTestData *async_data, gconstpointer service) \
109
tear_down_##CLOSURE_NAME ((TestStructType*) async_data->test_data, service); \
110
g_slice_free (TestStructType, (TestStructType*) async_data->test_data); \
111
gdata_tear_down_async_test_data (async_data, async_data->test_data); \
115
* GDATA_ASYNC_STARTING_TIMEOUT:
117
* The initial timeout for cancellation tests, which will be the first timeout used after testing cancelling the operation before it's started.
118
* The value is in milliseconds.
122
#define GDATA_ASYNC_STARTING_TIMEOUT 20 /* ms */
125
* GDATA_ASYNC_TIMEOUT_MULTIPLIER:
127
* The factor by which the asynchronous cancellation timeout will be multiplied between iterations of the cancellation test.
131
#define GDATA_ASYNC_TIMEOUT_MULTIPLIER 3
134
* GDATA_ASYNC_MAXIMUM_TIMEOUT:
136
* The maximum timeout value for cancellation tests before they fail. i.e. If an operation takes longer than this period of time, the asynchronous
137
* operation test will fail.
138
* The value is in milliseconds.
142
#define GDATA_ASYNC_MAXIMUM_TIMEOUT 43740 /* ms */
145
* GDATA_ASYNC_TEST_FUNCTIONS:
146
* @TEST_NAME: the name of the test, excluding the “test_” prefix and the “_async” suffix
147
* @TestStructType: type of the closure structure to use, or <type>void</type>
148
* @TEST_BEGIN_CODE: code to execute to begin the test and start the asynchronous call
149
* @TEST_END_CODE: code to execute once the asynchronous call has completed, which will check the return values and any changed state
151
* Defines test and callback functions to test normal asynchronous operation and the cancellation behaviour of the given asynchronous function call.
153
* The asynchronous function call should be started in @TEST_BEGIN_CODE, using <varname>cancellable</varname> as its #GCancellable parameter,
154
* <varname>async_ready_callback</varname> as its #GAsyncReadyCallback parameter and <varname>async_data</varname> as its <varname>user_data</varname>
155
* parameter. There is no need for the code to create its own main loop: that's taken care of by the wrapper code.
157
* The code in @TEST_END_CODE will be inserted into the callback function for both the normal asynchronous test and the cancellation test, so should
158
* finish the asynchronous function call, using <varname>obj</varname> as the object on which the asynchronous function call was made,
159
* <varname>async_result</varname> as its #GAsyncResult parameter and <varname>error</varname> as its #GError parameter. The code should then check
160
* <varname>error</code>: if it's %NULL, the code should assert success conditions; if it's non-%NULL, the code should assert failure conditions.
161
* The wrapper code will ensure that the error is a %G_IO_ERROR_CANCELLED at the appropriate times.
163
* The following functions will be defined, and should be added to the test suite using the #GAsyncTestData closure structure:
164
* <function>test_<replaceable>TEST_NAME</replaceable>_async</function> and
165
* <function>test_<replaceable>TEST_NAME</replaceable>_async_cancellation</function>.
169
#define GDATA_ASYNC_TEST_FUNCTIONS(TEST_NAME, TestStructType, TEST_BEGIN_CODE, TEST_END_CODE) \
171
test_##TEST_NAME##_async_cb (GObject *obj, GAsyncResult *async_result, GDataAsyncTestData *async_data) \
173
TestStructType *data = (TestStructType*) async_data->test_data; \
174
GError *error = NULL; \
176
(void) data; /* hide potential unused variable warning */ \
181
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) == TRUE) { \
182
g_assert (g_cancellable_is_cancelled (async_data->cancellable) == TRUE); \
183
async_data->cancellation_successful = TRUE; \
184
} else if (error == NULL) { \
185
g_assert (g_cancellable_is_cancelled (async_data->cancellable) == FALSE || async_data->cancellation_timeout > 0); \
186
async_data->cancellation_successful = FALSE; \
188
/* Unexpected error: explode. */ \
189
g_assert_no_error (error); \
190
async_data->cancellation_successful = FALSE; \
194
g_clear_error (&error); \
196
g_main_loop_quit (async_data->main_loop); \
200
test_##TEST_NAME##_async (GDataAsyncTestData *async_data, gconstpointer service) \
202
GAsyncReadyCallback async_ready_callback = (GAsyncReadyCallback) test_##TEST_NAME##_async_cb; \
203
TestStructType *data = (TestStructType*) async_data->test_data; \
204
GCancellable *cancellable = NULL; /* don't expose the cancellable, so the test proceeds as normal */ \
206
(void) data; /* hide potential unused variable warning */ \
208
/* Just run the test without doing any cancellation, and assert that it succeeds. */ \
209
async_data->cancellation_timeout = 0; \
211
g_test_message ("Running normal operation test…"); \
217
g_main_loop_run (async_data->main_loop); \
221
test_##TEST_NAME##_async_cancellation (GDataAsyncTestData *async_data, gconstpointer service) \
223
async_data->cancellation_timeout = 0; \
225
/* Starting with a short timeout, repeatedly run the async. operation, cancelling it after the timeout and increasing the timeout until
226
* the operation succeeds for the first time. We then finish the test. This guarantees that if, for example, the test creates an entry on
227
* the server, it only ever creates one; because the test only ever succeeds once. (Of course, this assumes that the server does not change
228
* state if we cancel the operation, which is a fairly optimistic assumption. Sigh.) */ \
230
GCancellable *cancellable = async_data->cancellable; \
231
GAsyncReadyCallback async_ready_callback = (GAsyncReadyCallback) test_##TEST_NAME##_async_cb; \
232
TestStructType *data = (TestStructType*) async_data->test_data; \
234
(void) data; /* hide potential unused variable warning */ \
236
/* Ensure the timeout remains sane. */ \
237
g_assert_cmpuint (async_data->cancellation_timeout, <=, GDATA_ASYNC_MAXIMUM_TIMEOUT); \
239
/* Schedule the cancellation after the timeout. */ \
240
if (async_data->cancellation_timeout == 0) { \
241
/* For the first test, cancel the cancellable before the test code is run */ \
242
gdata_async_test_cancellation_cb (async_data); \
244
async_data->cancellation_timeout_id = g_timeout_add (async_data->cancellation_timeout, \
245
(GSourceFunc) gdata_async_test_cancellation_cb, async_data); \
248
/* Mark the cancellation as unsuccessful and hope we get proven wrong. */ \
249
async_data->cancellation_successful = FALSE; \
251
g_test_message ("Running cancellation test with timeout of %u ms…", async_data->cancellation_timeout); \
257
g_main_loop_run (async_data->main_loop); \
259
/* Reset the cancellable for the next iteration and increase the timeout geometrically. */ \
260
g_cancellable_reset (cancellable); \
262
if (async_data->cancellation_timeout == 0) { \
263
async_data->cancellation_timeout = GDATA_ASYNC_STARTING_TIMEOUT; /* ms */ \
265
async_data->cancellation_timeout *= GDATA_ASYNC_TIMEOUT_MULTIPLIER; \
267
} while (async_data->cancellation_successful == TRUE); \
269
/* Clean up the last timeout callback */ \
270
if (async_data->cancellation_timeout_id != 0) { \
271
g_source_remove (async_data->cancellation_timeout_id); \
275
gboolean gdata_async_test_cancellation_cb (GDataAsyncTestData *async_data);
276
void gdata_set_up_async_test_data (GDataAsyncTestData *async_data, gconstpointer test_data);
277
void gdata_tear_down_async_test_data (GDataAsyncTestData *async_data, gconstpointer test_data);
57
281
#endif /* !GDATA_TEST_COMMON_H */