This is meant to simplify testing conditions that generally hold true but may occasionally fail due to interference from external factors (such as processes that start / stop, network connections being opened / closed, etc). The trick is to loop a few times on the set of flaky conditions until they succeed. During the last attempt all failures are recorded as usual, while in the previous runs, the tryok() failures area ignored but cause one more attempt to be made.
The simplest case looks like this: LOOP_ON_FLAKY_TESTS(3) { // ok() failures are never ignored and not retried ok(..., "check 1", ...); // tryok() failures are ignored except on the last attempt tryok(..., "check 2", ...); }
There is also: * attempt_retry() which marks the current attempt as failed as if calling tryok(0), and returns true if another attempt can be made. * attempt_failed() which returns true if an ok() call failed.
--- This is independent from the 'flaky' mechanism which adds some naming constraints. The loop macro is still called LOOP_ON_FLAKY_TESTS() despite being unrelated to the flaky mechanism. The attempt_retry() and attempt_failed() macro names also don't make it obvious that they are related to tryok().
I think this mechanism is better than the flaky one because a flaky test can go bad without anyone noticing, whereas if a tryok() starts failing systematically it will cause a real failure.
The other side of that coin is that, unlike flaky, the tryok() mechanism does not entirely eliminate the possibility of getting a failure, it just reduces it; though by adjusting the maximum number of attempts one can achieve an arbitrarily low failure rate. For instance if an ok() call fails 10% of the time and one wants a maximum of 1 in a million failure rate, use LOOP_ON_FLAKY_TESTS(6). The cost is an increased run time in the worst case.
This also limits the use of this mechanism to tests that have a reasonably low failure rate to start with (otherwise one has to loop too many times). Also note that there are cases where looping essentially reduce the failure rate to zero. For instance ieframe:webbrowser fails if IE creates a net session while the test is counting them. But IE only creates the one net session on start up so trying even one more time should guarantee that the test will succeed. Other cases like scheduling delays and the creation of network connections are more probabilistic in nature. Maybe a comment in test.h should offer some guideline as to the target failure rate.
Eventually this may replace the flaky mechanism but that depends on how well it works in practice and how practical it is to loop on flaky tests. It seems to be going well in the few cases I looked at. But I think this mechanism has value even if the two end up coexisting indefinitely.
This MR uses the tryok() in some actual tests for illustration and testing purposes. The final MR will probably split most of those off to separate MRs.
-- v5: ieframe/tests: Work around a network session race condition. advapi32/tests: Replace the custom loop with the tryok() mechanism. ntdll/tests: Use tryok() to fix a free disk space race with other processes. kernel32/tests: Use tryok() to fix a heap race with other processes. tests: Add tryok() for tests that sometimes get outside interference. tests: Update the documentation.
From: Francois Gouget fgouget@codeweavers.com
--- include/wine/test.h | 74 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 5 deletions(-)
diff --git a/include/wine/test.h b/include/wine/test.h index 73d6d164c46..d531d052383 100644 --- a/include/wine/test.h +++ b/include/wine/test.h @@ -242,6 +242,13 @@ static void exit_process( int code ) }
+/* Records the location of the next check. + * See the xxx_(file, line) macros. + * + * Parameters: + * - file - source file name of the check + * - line - source line number of the check + */ void winetest_set_location( const char* file, int line ) { struct tls_data *data = get_tls_data(); @@ -353,12 +360,13 @@ static LONG winetest_add_line( void ) }
/* - * Checks condition. + * Checks that a condition has the expected value, that is true except if + * preceded by a todo indicating the check is expected to fail. + * * Parameters: - * - condition - condition to check; - * - msg test description; - * - file - test application source code file name of the check - * - line - test application source code file line number of the check + * - condition - true if the check succeeded, false otherwise; + * - msg - failure message format; + * - args - arguments for the failure message * Return: * 0 if condition does not have the expected value, 1 otherwise */ @@ -478,6 +486,14 @@ void winetest_trace( const char *msg, ... ) InterlockedIncrement(&muted_traces); }
+/* + * Prints a message to indicate that a group of tests is being skipped + * because the requirements for running them are not met. + * + * Parameters: + * - msg - failure message format; + * - args - arguments for the failure message + */ void winetest_vskip( const char *msg, va_list args ) { if (winetest_add_line() < winetest_mute_threshold) @@ -502,6 +518,10 @@ void winetest_skip( const char *msg, ... ) va_end(valist); }
+/* Same as winetest_skip() on Windows and a test failure otherwise. Typically + * used when a required Windows API or functionality is missing, since those + * should not be missing in Wine. + */ void winetest_win_skip( const char *msg, ... ) { va_list valist; @@ -513,6 +533,18 @@ void winetest_win_skip( const char *msg, ... ) va_end(valist); }
+/* If is_flaky is true, indicates that the next test may occasionally fail due + * to unavoidable outside race conditions. Such failures will be flagged as + * flaky so they can be ignored by automated testing tools. + * + * Remarks: + * - This is not meant to paper over race conditions within the test itself. + * Those are bugs and should be fixed. + * - This is not meant to be used for tests that normally succeed but + * systematically fail on a specific platform or locale. + * - The failures should be rare to start with. If a test fails 25% of the time + * it is probably wrong. + */ void winetest_start_flaky( int is_flaky ) { struct tls_data *data = get_tls_data(); @@ -534,6 +566,13 @@ void winetest_end_flaky(void) data->flaky_level >>= 1; }
+/* If is_todo is true, indicates that the next test is expected to fail on this + * platform. This is used to identify tests that are known to fail in Wine. + * + * Remarks: + * - is_todo should never be true on Windows. To ensure this, always use + * todo_wine_if(). + */ void winetest_start_todo( int is_todo ) { struct tls_data *data = get_tls_data(); @@ -555,6 +594,31 @@ void winetest_end_todo(void) data->todo_level >>= 1; }
+/* Adds a string to be prepended to the test traces and failure messages. + * This must be paired with a winetest_pop_context() call. + * + * Parameters: + * - msg - failure message format; + * - args - arguments for the failure message + * + * Remarks: + * - Failure messages must always make it possible to figure out what was being + * tested. While not ideal the line number can usually be used for that + * purpose except when the test loops on a list of test parameters. In such + * cases either the test parameters or the loop index should be added to the + * context. + * + * Example: + * + * for (i = 0; i < ARRAY_SIZE(test_parameters); i++) + * { + * winetest_push_context("%d", i); + * ... + * ok(WinAPI(test_parameters[i]), ...); + * ... + * winetest_pop_context(); + * } + */ void winetest_push_context( const char *fmt, ... ) { struct tls_data *data = get_tls_data();
From: Francois Gouget fgouget@codeweavers.com
This is meant to simplify testing conditions that generally hold true but may occasionally fail due to interference from external factors (such as processes that start / stop, network connections being opened / closed, etc).
The trick is loop a few times on the set of flaky conditions until they succeed. During the last attempt all failures are recorded as usual, while in the previous runs, tryok() failures are ignored but cause one more attempt to be run.
The simplest case looks like this:
LOOP_ON_FLAKY_TESTS(3) { // ok() failures are never ignored and not retried ok(..., "check 1", ...); // tryok() failures are ignored except on the last attempt tryok(..., "check 2", ...); }
There is also: * attempt_retry() which indicate a new attempt is needed without counting as a failure, and returns true if a new attempt is possible. * attempt_failed() which returns true if the current attempt failed.
--- This is independent from the 'flaky' mechanism which adds some naming constraints. The loop macro is still called LOOP_ON_FLAKY_TESTS() despite being unrelated to the flaky mechanism. The attempt_retry() and attempt_failed() macro names also don't make it obvious that they are related to tryok().
I think this mechanism is better than the flaky one because a flaky test can go bad without anyone noticing, whereas if a tryok() starts failing systematically it will cause a real failure.
The other side of that coin is that, unlike flaky, the tryok() mechanism does not entirely eliminate the possibility of getting a failure, it just reduces it; though by adjusting the maximum number of attempts one can achieve an arbitrarily low failure rate. For instance if an ok() call fails 10% of the time and one wants a maximum of 1 in a million failure rate, use LOOP_ON_FLAKY_TESTS(6). The cost is an increased run time in the worst case.
This also limits the use of this mechanism to tests that have a reasonably low failure rate to start with (otherwise one has to loop too many times). Also note that there are cases where looping essentially reduce the failure rate to zero. For instance ieframe:webbrowser fails if IE creates a net session while the test is counting them. But IE only creates the one net session on start up so trying even one more time should guarantee that the test will succeed. Other cases like scheduling delays and the creation of network connections are more probabilistic in nature. Maybe a comment in test.h should offer some guideline as to the target failure rate.
Eventually this may replace the flaky mechanism but that depends on how well it works in practice and how practical it is to loop on flaky tests. It seems to be going well in the cases I looked at. I think this mechanism has value even if the two end up coexisting indefinitely. --- dlls/kernel32/tests/debugger.c | 2 +- include/wine/test.h | 225 ++++++++++++++++++++++++++++++++- 2 files changed, 220 insertions(+), 7 deletions(-)
diff --git a/dlls/kernel32/tests/debugger.c b/dlls/kernel32/tests/debugger.c index b0c69052936..3ec3133e7a7 100644 --- a/dlls/kernel32/tests/debugger.c +++ b/dlls/kernel32/tests/debugger.c @@ -63,7 +63,7 @@ static void WINAPIV __WINE_PRINTF_ATTR(2, 3) test_child_ok(int condition, const va_list valist;
va_start(valist, msg); - winetest_vok(condition, msg, valist); + winetest_vok(condition, 0, msg, valist); va_end(valist); if (!condition) ++child_failures; } diff --git a/include/wine/test.h b/include/wine/test.h index d531d052383..de38835ff9d 100644 --- a/include/wine/test.h +++ b/include/wine/test.h @@ -80,10 +80,11 @@ extern void winetest_wait_child_process( HANDLE process ); #endif
extern int broken( int condition ); -extern int winetest_vok( int condition, const char *msg, va_list ap ); +extern int winetest_vok( int condition, BOOL trying, const char *msg, va_list ap ); extern void winetest_vskip( const char *msg, va_list ap );
extern void winetest_ok( int condition, const char *msg, ... ) __WINE_PRINTF_ATTR(2,3); +extern void winetest_tryok( int condition, const char *msg, ... ) __WINE_PRINTF_ATTR(2,3); extern void winetest_skip( const char *msg, ... ) __WINE_PRINTF_ATTR(1,2); extern void winetest_win_skip( const char *msg, ... ) __WINE_PRINTF_ATTR(1,2); extern void winetest_trace( const char *msg, ... ) __WINE_PRINTF_ATTR(1,2); @@ -91,27 +92,46 @@ extern void winetest_trace( const char *msg, ... ) __WINE_PRINTF_ATTR(1,2); extern void winetest_push_context( const char *fmt, ... ) __WINE_PRINTF_ATTR(1, 2); extern void winetest_pop_context(void);
+extern void winetest_start_attempt( int retries ); +extern int winetest_loop_attempt( void ); +extern void winetest_end_attempt( void ); +extern BOOL winetest_attempt_retry( BOOL condition ); +extern BOOL winetest_attempt_failed( void ); + #ifdef WINETEST_NO_LINE_NUMBERS # define subtest_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_subtest # define ignore_exceptions_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_ignore_exceptions # define ok_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_ok +# define tryok_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_tryok # define skip_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_skip # define win_skip_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_win_skip # define trace_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_trace # define wait_child_process_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_wait_child_process +# define start_attempt_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_start_attempt +# define loop_attempt_(file, line) (winetest_set_location(file, 0), 0) ? 0 : winetest_loop_attempt +# define end_attempt_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_end_attempt +# define attempt_retry_(file, line) (winetest_set_location(file, 0), 0) ? 0 : winetest_attempt_retry +# define attempt_failed_(file, line) (winetest_set_location(file, 0), 0) ? 0 : winetest_attempt_failed #else # define subtest_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_subtest # define ignore_exceptions_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_ignore_exceptions # define ok_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_ok +# define tryok_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_tryok # define skip_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_skip # define win_skip_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_win_skip # define trace_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_trace # define wait_child_process_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_wait_child_process +# define start_attempt_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_start_attempt +# define loop_attempt_(file, line) (winetest_set_location(file, line), 0) ? 0 : winetest_loop_attempt +# define end_attempt_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_end_attempt +# define attempt_retry_(file, line) (winetest_set_location(file, line), 0) ? 0 : winetest_attempt_retry +# define attempt_failed_(file, line) (winetest_set_location(file, line), 0) ? 0 : winetest_attempt_failed #endif
#define subtest subtest_(__FILE__, __LINE__) #define ignore_exceptions ignore_exceptions_(__FILE__, __LINE__) #define ok ok_(__FILE__, __LINE__) +#define tryok tryok_(__FILE__, __LINE__) #define skip skip_(__FILE__, __LINE__) #define win_skip win_skip_(__FILE__, __LINE__) #define trace trace_(__FILE__, __LINE__) @@ -130,6 +150,17 @@ extern void winetest_pop_context(void); #define todo_wine todo_if(!strcmp(winetest_platform, "wine")) #define todo_wine_if(is_todo) todo_if((is_todo) && !strcmp(winetest_platform, "wine"))
+#define start_attempt start_attempt_(__FILE__, __LINE__) +#define loop_attempt loop_attempt_(__FILE__, __LINE__) +#define end_attempt end_attempt_(__FILE__, __LINE__) +#define attempt_retry attempt_retry_(__FILE__, __LINE__) +#define attempt_failed attempt_failed_(__FILE__, __LINE__) +#define LOOP_ON_FLAKY_TESTS(count) for (start_attempt((count) - 1); \ + loop_attempt(); \ + end_attempt()) +#define LOOP_ON_FLAKY_WINDOWS_TESTS(count) LOOP_ON_FLAKY_TESTS(strcmp(winetest_platform, "windows") == 0 ? (count) : 1) +#define LOOP_ON_FLAKY_WINE_TESTS(count) LOOP_ON_FLAKY_TESTS(strcmp(winetest_platform, "windows") == 0 ? 1 : (count)) +
#ifndef ARRAY_SIZE # define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) @@ -202,6 +233,12 @@ static LONG muted_todo_successes; /* same as todo_successes but silent */ /* counts how many times a given line printed a message */ static LONG line_counters[16384];
+#define ATTEMPT_NONE 0 +#define ATTEMPT_STARTED 1 +#define ATTEMPT_RETRY 2 +#define ATTEMPT_BADOK 4 +#define ATTEMPT_FAILED (ATTEMPT_RETRY | ATTEMPT_BADOK) + /* The following data must be kept track of on a per-thread basis */ struct tls_data { @@ -215,6 +252,8 @@ struct tls_data char strings[2000]; /* buffer for debug strings */ char context[8][128]; /* data to print before messages */ unsigned int context_count; /* number of context prefixes */ + int attempt_status; + int attempt_retries; }; static DWORD tls_index;
@@ -229,6 +268,8 @@ static struct tls_data *get_tls_data(void) { data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data)); data->str_pos = data->strings; + data->attempt_status = ATTEMPT_NONE; + data->attempt_retries = 0; TlsSetValue(tls_index,data); } SetLastError(last_error); @@ -365,12 +406,13 @@ static LONG winetest_add_line( void ) * * Parameters: * - condition - true if the check succeeded, false otherwise; + * - trying - if non-zero the failure may be ignored if in an attempt loop; * - msg - failure message format; * - args - arguments for the failure message * Return: * 0 if condition does not have the expected value, 1 otherwise */ -int winetest_vok( int condition, const char *msg, va_list args ) +int winetest_vok( int condition, BOOL trying, const char *msg, va_list args ) { struct tls_data *data = get_tls_data();
@@ -379,12 +421,23 @@ int winetest_vok( int condition, const char *msg, va_list args ) if (condition) { winetest_print_lock(); - if (data->flaky_level) + if (trying && data->attempt_retries > 0) + { + if (winetest_report_success || + (winetest_time && GetTickCount() >= winetest_last_time + 1000)) + { + winetest_print_context( data->flaky_level ? "Retry successful test inside flaky todo block: " : "Retry successful test inside todo block: "); + vprintf(msg, args); + } + data->attempt_status |= ATTEMPT_RETRY; + } + else if (data->flaky_level) { if (winetest_color) printf( color_dark_purple ); winetest_print_context( "Test succeeded inside flaky todo block: " ); vprintf(msg, args); InterlockedIncrement(&flaky_failures); + data->attempt_status |= ATTEMPT_BADOK; } else { @@ -392,6 +445,7 @@ int winetest_vok( int condition, const char *msg, va_list args ) winetest_print_context( "Test succeeded inside todo block: " ); vprintf(msg, args); InterlockedIncrement(&todo_failures); + data->attempt_status |= ATTEMPT_BADOK; } if (winetest_color) printf( color_reset ); winetest_print_unlock(); @@ -423,12 +477,23 @@ int winetest_vok( int condition, const char *msg, va_list args ) if (!condition) { winetest_print_lock(); - if (data->flaky_level) + if (trying && data->attempt_retries > 0) + { + if (winetest_report_success || + (winetest_time && GetTickCount() >= winetest_last_time + 1000)) + { + winetest_print_context( data->flaky_level ? "Retry flaky test: " : "Retry failed test: "); + vprintf(msg, args); + } + data->attempt_status |= ATTEMPT_RETRY; + } + else if (data->flaky_level) { if (winetest_color) printf( color_bright_purple ); winetest_print_context( "Test marked flaky: " ); vprintf(msg, args); InterlockedIncrement(&flaky_failures); + data->attempt_status |= ATTEMPT_BADOK; } else { @@ -436,6 +501,7 @@ int winetest_vok( int condition, const char *msg, va_list args ) winetest_print_context( "Test failed: " ); vprintf(msg, args); InterlockedIncrement(&failures); + data->attempt_status |= ATTEMPT_BADOK; } if (winetest_color) printf( color_reset ); winetest_print_unlock(); @@ -463,7 +529,7 @@ void winetest_ok( int condition, const char *msg, ... ) va_list valist;
va_start(valist, msg); - winetest_vok(condition, msg, valist); + winetest_vok(condition, FALSE, msg, valist); va_end(valist); }
@@ -529,7 +595,154 @@ void winetest_win_skip( const char *msg, ... ) if (strcmp(winetest_platform, "windows") == 0) winetest_vskip(msg, valist); else - winetest_vok(0, msg, valist); + winetest_vok(0, FALSE, msg, valist); + va_end(valist); +} + +/* Starts a group of tests that has a low but non-zero probability of failing + * due to unavoidable outside interference. This means it may be necessary + * to retry a few times to get a successful run. + * + * Parameters: + * - retries - The number of times this group of tests should be retried if it + * fails. + * + * Remarks: + * - Nesting attempts is not allowed and results in a failure. + * - As a corollary, do not break out of an attempt loop. + * - This is not meant to paper over race conditions within the test itself. + * Those are bugs and should be fixed. + * - The failures should be rare to start with. If a test fails 25% of the time + * or needs to be repeated more than a handful of times to succeed reliably + * it is probably wrong. + * + * Examples: + * + * LOOP_ON_FLAKY_TESTS(3) + * { + * ... + * // ok() failures are never ignored and not retried + * ok(..., "check 1", ...); + * + * // ignore tryok() failures except on the last attempt + * tryok(..., "check 2", ...); + * ... + * } + * + * LOOP_ON_FLAKY_TESTS(5) + * { + * ... + * // if the conditions for running the remaining tests are not met, + * // pass true to indicate this attempt failed and a new one should + * // be made. attempt_retry() will return true if that is possible. + * if (attempt_retry(condition)) + * continue; + * ok(..., "check 1", ...); + * + * ... + * // skip if an ok() or tryok() failed already + * if (attempt_failed()) continue; + * ... + * } + */ +void winetest_start_attempt( int retries ) +{ + struct tls_data *data = get_tls_data(); + + if (data->attempt_status & ATTEMPT_STARTED) + winetest_ok(0, "nesting attempt blocks is not allowed (%x/%d)\n", data->attempt_status, data->attempt_retries); + data->attempt_retries = retries; + data->attempt_status = ATTEMPT_STARTED | ATTEMPT_RETRY; +} + +int winetest_loop_attempt( void ) +{ + struct tls_data *data = get_tls_data(); + + if (!(data->attempt_status & ATTEMPT_FAILED) || /* no failure */ + (data->attempt_status & ATTEMPT_BADOK) || /* unrecoverable failure */ + data->attempt_retries < 0) /* no retries left */ + { + data->attempt_status = ATTEMPT_NONE; + data->attempt_retries = 0; + return FALSE; /* exit loop */ + } + + winetest_push_context("r%d", data->attempt_retries); + data->attempt_status = ATTEMPT_STARTED; + return TRUE; +} + +void winetest_end_attempt( void ) +{ + struct tls_data *data = get_tls_data(); + + winetest_pop_context(); + data->attempt_retries--; +} + +/* Marks the current attempt as failed if condition is true and returns + * whether another attempt is needed and possible. + * + * Parameters: + * - condition - True to indicate that the conditions for running the + * remaining tests are not met and a new attempt should be made. + * This never counts as a test failure. + * + * Return: + * True if the current attempt failed and a new attempt can be made. + * The current attempt is considered to be failed if either condition is + * true or a tryok() call failed already. + * + * Remarks: + * - A new attempt is needed if either condition is true, or a tryok() call + * failed. + * - Plain ok() failures are final so no new attempt is needed after those. + * - This always returns false if not in an attempt loop. + */ +BOOL winetest_attempt_retry( BOOL condition ) +{ + struct tls_data *data = get_tls_data(); + + if (!(data->attempt_status & ATTEMPT_STARTED) || /* not in a retry loop */ + (data->attempt_status & ATTEMPT_BADOK) || /* unrecoverable failure */ + !data->attempt_retries || /* no retries left */ + (!condition && !(data->attempt_status & ATTEMPT_RETRY))) /* no need to retry */ + return FALSE; + data->attempt_status |= ATTEMPT_RETRY; + return TRUE; +} + +/* Returns true if the current attempt failed, whether because of a tryok() + * or a plain ok() call. + * + * Remarks: + * - This always returns false if not in an attempt loop. + */ +BOOL winetest_attempt_failed( void ) +{ + struct tls_data *data = get_tls_data(); + + return (data->attempt_status & ATTEMPT_STARTED) && + (data->attempt_status & ATTEMPT_FAILED); +} + + +/* Performs a check that may need to be repeated to avoid failures caused by + * race conditions. See winetest_start_attempt() for details. + * + * Parameters: see winetest_ok() + * + * Remarks: + * - If not in an attempt loop this behaves the same as a regular ok() call. + */ +void winetest_tryok( int condition, const char *msg, ... ) +{ + struct tls_data *data = get_tls_data(); + va_list valist; + + va_start(valist, msg); + winetest_vok(condition, data->attempt_status & ATTEMPT_STARTED, msg, valist); va_end(valist); }
From: Francois Gouget fgouget@codeweavers.com
If other processes allocate or free enough memory (e.g. by terminating), the available physical memory and swap space reported by the system may change while testing these values.
Wine-Bug: https://bugs.winehq.org//show_bug.cgi?id=54498 --- dlls/kernel32/tests/heap.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index 24ce6b792da..ec5f074cf85 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -3624,9 +3624,11 @@ static void test_GlobalMemoryStatus(void)
ok( memex.dwMemoryLoad == expect.dwMemoryLoad, "got dwMemoryLoad %lu\n", memex.dwMemoryLoad ); ok( memex.ullTotalPhys == expect.ullTotalPhys, "got ullTotalPhys %#I64x\n", memex.ullTotalPhys ); - ok( IS_WITHIN_RANGE( memex.ullAvailPhys, expect.ullAvailPhys ), "got ullAvailPhys %#I64x\n", memex.ullAvailPhys ); + /* ullAvailPhys may change if a big process starts / stops */ + tryok( IS_WITHIN_RANGE( memex.ullAvailPhys, expect.ullAvailPhys ), "got ullAvailPhys %#I64x\n", memex.ullAvailPhys ); ok( memex.ullTotalPageFile == expect.ullTotalPageFile, "got ullTotalPageFile %#I64x\n", memex.ullTotalPageFile ); - ok( IS_WITHIN_RANGE( memex.ullAvailPageFile, expect.ullAvailPageFile ), "got ullAvailPageFile %#I64x\n", memex.ullAvailPageFile ); + /* ullAvailPageFile may change if a big process starts / stops */ + tryok( IS_WITHIN_RANGE( memex.ullAvailPageFile, expect.ullAvailPageFile ), "got ullAvailPageFile %#I64x\n", memex.ullAvailPageFile ); ok( memex.ullTotalVirtual == expect.ullTotalVirtual, "got ullTotalVirtual %#I64x\n", memex.ullTotalVirtual ); ok( memex.ullAvailVirtual <= expect.ullAvailVirtual, "got ullAvailVirtual %#I64x\n", memex.ullAvailVirtual ); ok( memex.ullAvailExtendedVirtual == 0, "got ullAvailExtendedVirtual %#I64x\n", memex.ullAvailExtendedVirtual ); @@ -3749,7 +3751,7 @@ START_TEST(heap) test_LocalAlloc();
test_GetPhysicallyInstalledSystemMemory(); - test_GlobalMemoryStatus(); + LOOP_ON_FLAKY_TESTS(3) test_GlobalMemoryStatus();
if (pRtlGetNtGlobalFlags) {
From: Francois Gouget fgouget@codeweavers.com
The test would fail if other processes allocate or free disk space in between the FileFsFullSizeInformation and FileFsSizeInformation calls.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55365 --- dlls/ntdll/tests/file.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 556ba351809..f2d17598fc4 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -1317,7 +1317,8 @@ static void test_file_full_size_information(void) "[ffsi] TotalAllocationUnits error fsi:0x%s, ffsi:0x%s\n", wine_dbgstr_longlong(fsi.TotalAllocationUnits.QuadPart), wine_dbgstr_longlong(ffsi.TotalAllocationUnits.QuadPart)); - ok(ffsi.CallerAvailableAllocationUnits.QuadPart == fsi.AvailableAllocationUnits.QuadPart, + /* Other processes may have allocated or freed disk space */ + tryok(ffsi.CallerAvailableAllocationUnits.QuadPart == fsi.AvailableAllocationUnits.QuadPart, "[ffsi] CallerAvailableAllocationUnits error fsi:0x%s, ffsi: 0x%s\n", wine_dbgstr_longlong(fsi.AvailableAllocationUnits.QuadPart), wine_dbgstr_longlong(ffsi.CallerAvailableAllocationUnits.QuadPart)); @@ -5666,7 +5667,7 @@ START_TEST(file) test_file_all_information(); test_file_both_information(); test_file_name_information(); - test_file_full_size_information(); + LOOP_ON_FLAKY_TESTS(3) test_file_full_size_information(); test_file_all_name_information(); test_file_rename_information(); test_file_link_information();
From: Francois Gouget fgouget@codeweavers.com
The custom loop was meant to work around the race condition with services being started / stopped by Windows while the test is running. The tryok() mechanism provides the same functionality in a simpler to use and standardized form. Also this is really only needed on Windows so use LOOP_ON_FLAKY_WINDOWS_TESTS(). --- dlls/advapi32/tests/service.c | 123 ++++++++++++++++------------------ 1 file changed, 56 insertions(+), 67 deletions(-)
diff --git a/dlls/advapi32/tests/service.c b/dlls/advapi32/tests/service.c index 8cc737207e0..c90237fad8f 100644 --- a/dlls/advapi32/tests/service.c +++ b/dlls/advapi32/tests/service.c @@ -1062,10 +1062,10 @@ static void test_query_svc(void) CloseServiceHandle(scm_handle); }
-static BOOL test_enum_svc(int attempt) +static void test_enum_svc(void) { SC_HANDLE scm_handle; - BOOL ret, alldone = FALSE; + BOOL ret; DWORD bufsize, needed, returned, resume; DWORD neededA, returnedA; DWORD tempneeded, tempreturned, missing; @@ -1266,9 +1266,8 @@ static BOOL test_enum_svc(int attempt) "Expected ERROR_MORE_DATA, got %ld\n", GetLastError()); ok(neededA != 0xdeadbeef && neededA > 0, "Expected the needed buffer size for this one service\n"); ok(returnedA == 0, "Expected no service returned, got %ld\n", returnedA); - if (neededA != needed && attempt) - goto retry; /* service start|stop race condition */ - ok(neededA == needed, "Expected needed buffersize to be the same for A- and W-calls\n"); + tryok(neededA == needed, "Expected needed buffersize to be the same for A- and W-calls\n"); + if (attempt_failed()) goto cleanup; /* service start|stop race condition */
/* Store the needed bytes */ tempneeded = needed; @@ -1282,8 +1281,8 @@ static BOOL test_enum_svc(int attempt) ret = EnumServicesStatusW(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, services, bufsize, &needed, &returned, NULL); HeapFree(GetProcessHeap(), 0, services); - if (!ret && GetLastError() == ERROR_MORE_DATA && attempt) - goto retry; /* service start race condition */ + if (attempt_retry(!ret && GetLastError() == ERROR_MORE_DATA)) + goto cleanup; /* service start|stop race condition */ ok(ret, "Expected success, got error %lu\n", GetLastError()); ok(needed == 0, "Expected needed buffer to be 0 as we are done\n"); ok(returned != 0xdeadbeef && returned > 0, "Expected some returned services\n"); @@ -1299,8 +1298,8 @@ static BOOL test_enum_svc(int attempt) ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, servicesA, bufsize, &neededA, &returnedA, NULL); HeapFree(GetProcessHeap(), 0, servicesA); - if (!ret && GetLastError() == ERROR_MORE_DATA && attempt) - goto retry; /* service start race condition */ + if (attempt_retry(!ret && GetLastError() == ERROR_MORE_DATA)) + goto cleanup; /* service start race condition */ if (!ret && GetLastError() == ERROR_NOT_ENOUGH_MEMORY && GetACP() == CP_UTF8) win_skip("Skipping some tests due to EnumServicesStatusA()'s broken UTF-8 support\n"); else @@ -1321,10 +1320,10 @@ static BOOL test_enum_svc(int attempt) SetLastError(0xdeadbeef); ret = EnumServicesStatusW(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, services, bufsize, &needed, &returned, NULL); - if (ret && needed == 0 && attempt) + if (attempt_retry(ret && needed == 0)) { HeapFree(GetProcessHeap(), 0, services); - goto retry; /* service stop race condition */ + goto cleanup; /* service stop race condition */ } ok(!ret, "Expected failure\n"); ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size\n"); @@ -1344,10 +1343,10 @@ static BOOL test_enum_svc(int attempt) SetLastError(0xdeadbeef); ret = EnumServicesStatusW(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, services, bufsize, &needed, &returned, &resume); - if (ret && needed == 0 && attempt) + if (attempt_retry(ret && needed == 0)) { HeapFree(GetProcessHeap(), 0, services); - goto retry; /* service stop race condition */ + goto cleanup; /* service stop race condition */ } ok(!ret, "Expected failure\n"); ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size for the missing services, got %lx\n", needed); @@ -1366,8 +1365,8 @@ static BOOL test_enum_svc(int attempt) ret = EnumServicesStatusW(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, services, bufsize, &needed, &returned, &resume); HeapFree(GetProcessHeap(), 0, services); - if (!ret && GetLastError() == ERROR_MORE_DATA && attempt) - goto retry; /* service start race condition */ + if (attempt_retry(!ret && GetLastError() == ERROR_MORE_DATA)) + goto cleanup; /* service start race condition */ ok(ret, "Expected success, got error %lu\n", GetLastError()); ok(needed == 0, "Expected 0 needed bytes as we are done, got %lu\n", needed); todo_wine ok(returned == missing, "Expected %lu remaining services, got %lu\n", missing, returned); @@ -1392,8 +1391,8 @@ static BOOL test_enum_svc(int attempt) ret = EnumServicesStatusW(scm_handle, SERVICE_WIN32, SERVICE_ACTIVE, services, needed, &needed, &returned, NULL); HeapFree(GetProcessHeap(), 0, services); - if (!ret && GetLastError() == ERROR_MORE_DATA && attempt) - goto retry; /* service start race condition */ + if (attempt_retry(!ret && GetLastError() == ERROR_MORE_DATA)) + goto cleanup; /* service start race condition */
servicecountactive = returned;
@@ -1404,8 +1403,8 @@ static BOOL test_enum_svc(int attempt) ret = EnumServicesStatusW(scm_handle, SERVICE_WIN32, SERVICE_INACTIVE, services, needed, &needed, &returned, NULL); HeapFree(GetProcessHeap(), 0, services); - if (!ret && GetLastError() == ERROR_MORE_DATA && attempt) - goto retry; /* service start race condition */ + if (attempt_retry(!ret && GetLastError() == ERROR_MORE_DATA)) + goto cleanup; /* service start race condition */
servicecountinactive = returned;
@@ -1416,12 +1415,12 @@ static BOOL test_enum_svc(int attempt) ret = EnumServicesStatusW(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, services, needed, &needed, &returned, NULL); HeapFree(GetProcessHeap(), 0, services); - if (!ret && GetLastError() == ERROR_MORE_DATA && attempt) - goto retry; /* service start race condition */ + if (attempt_retry(!ret && GetLastError() == ERROR_MORE_DATA)) + goto cleanup; /* service start race condition */
/* Check if total is the same as active and inactive win32 services */ - if (returned != servicecountactive + servicecountinactive && attempt) - goto retry; /* service start|stop race condition */ + if (attempt_retry(returned != servicecountactive + servicecountinactive)) + goto cleanup; /* service start|stop race condition */ ok(returned == servicecountactive + servicecountinactive, "Expected service count %ld == %ld + %ld\n", returned, servicecountactive, servicecountinactive); @@ -1436,8 +1435,8 @@ static BOOL test_enum_svc(int attempt) services = HeapAlloc(GetProcessHeap(), 0, needed); ret = EnumServicesStatusW(scm_handle, SERVICE_DRIVER | SERVICE_WIN32, SERVICE_STATE_ALL, services, needed, &needed, &returned, NULL); - if (!ret && GetLastError() == ERROR_MORE_DATA && attempt) - goto retry; /* service start race condition */ + if (attempt_retry(!ret && GetLastError() == ERROR_MORE_DATA)) + goto cleanup; /* service start race condition */ ok(ret, "Expected success %lu\n", GetLastError());
/* Loop through all those returned drivers and services */ @@ -1482,22 +1481,19 @@ static BOOL test_enum_svc(int attempt) } HeapFree(GetProcessHeap(), 0, services);
- if ((servicecountactive || servicecountinactive) && attempt) - goto retry; /* service start|stop race condition */ + if (attempt_retry(servicecountactive || servicecountinactive)) + goto cleanup; /* service start|stop race condition */ ok(servicecountactive == 0, "Active services mismatch %lu\n", servicecountactive); ok(servicecountinactive == 0, "Inactive services mismatch %lu\n", servicecountinactive);
- alldone = TRUE; - -retry: +cleanup: CloseServiceHandle(scm_handle); - return alldone; }
-static BOOL test_enum_svc_ex(int attempt) +static void test_enum_svc_ex(void) { SC_HANDLE scm_handle; - BOOL ret, alldone = FALSE; + BOOL ret; DWORD bufsize, needed, returned, resume; DWORD neededA, returnedA; DWORD tempneeded, tempreturned, missing; @@ -1510,7 +1506,7 @@ static BOOL test_enum_svc_ex(int attempt) if (!pEnumServicesStatusExA) { win_skip( "EnumServicesStatusExA not available\n" ); - return TRUE; + return; }
/* All NULL or wrong */ @@ -1681,9 +1677,8 @@ static BOOL test_enum_svc_ex(int attempt) "Expected ERROR_MORE_DATA, got %ld\n", GetLastError()); ok(neededA != 0xdeadbeef && neededA > 0, "Expected the needed buffer size for this one service\n"); ok(returnedA == 0, "Expected no service returned, got %ld\n", returnedA); - if (neededA != needed && attempt) - goto retry; /* service start|stop race condition */ ok(neededA == needed, "Expected needed buffersize to be the same for A- and W-calls\n"); + if (attempt_failed()) goto cleanup; /* service start|stop race condition */ ok(GetLastError() == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %ld\n", GetLastError());
@@ -1698,8 +1693,8 @@ static BOOL test_enum_svc_ex(int attempt) ret = EnumServicesStatusW(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, services, needed, &needed, &returned, NULL); HeapFree(GetProcessHeap(), 0, services); - if (!ret && GetLastError() == ERROR_MORE_DATA && attempt) - goto retry; /* service start race condition */ + if (attempt_retry(!ret && GetLastError() == ERROR_MORE_DATA)) + goto cleanup; /* service start race condition */ ok(ret, "Expected success, got error %lu\n", GetLastError()); ok(needed == 0, "Expected needed buffer to be 0 as we are done\n"); ok(returned != 0xdeadbeef && returned > 0, "Expected some returned services\n"); @@ -1716,8 +1711,8 @@ static BOOL test_enum_svc_ex(int attempt) ret = pEnumServicesStatusExW(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, (BYTE*)exservices, bufsize, &needed, &returned, NULL, NULL); HeapFree(GetProcessHeap(), 0, exservices); - if (!ret && GetLastError() == ERROR_MORE_DATA && attempt) - goto retry; /* service start race condition */ + if (attempt_retry(!ret && GetLastError() == ERROR_MORE_DATA)) + goto cleanup; /* service start race condition */ ok(ret, "Expected success, got error %lu\n", GetLastError()); ok(needed == 0, "Expected needed buffer to be 0 as we are done\n"); ok(returned == tempreturned, "Expected the same number of service from this function\n"); @@ -1736,10 +1731,10 @@ static BOOL test_enum_svc_ex(int attempt) SetLastError(0xdeadbeef); ret = pEnumServicesStatusExW(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, (BYTE*)exservices, bufsize, &needed, &returned, NULL, NULL); - if (ret && needed == 0 && attempt) + if (attempt_retry(ret && needed == 0)) { HeapFree(GetProcessHeap(), 0, exservices); - goto retry; /* service stop race condition */ + goto cleanup; /* service stop race condition */ } ok(!ret, "Expected failure\n"); ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size for the missing services\n"); @@ -1759,10 +1754,10 @@ static BOOL test_enum_svc_ex(int attempt) SetLastError(0xdeadbeef); ret = pEnumServicesStatusExW(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, (BYTE*)exservices, bufsize, &needed, &returned, &resume, NULL); - if (ret && needed == 0 && attempt) + if (attempt_retry(ret && needed == 0)) { HeapFree(GetProcessHeap(), 0, exservices); - goto retry; /* service stop race condition */ + goto cleanup; /* service stop race condition */ } ok(!ret, "Expected failure\n"); ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size for the missing services\n"); @@ -1781,8 +1776,8 @@ static BOOL test_enum_svc_ex(int attempt) ret = pEnumServicesStatusExW(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, (BYTE*)exservices, bufsize, &needed, &returned, &resume, NULL); HeapFree(GetProcessHeap(), 0, exservices); - if (!ret && GetLastError() == ERROR_MORE_DATA && attempt) - goto retry; /* service start race condition */ + if (attempt_retry(!ret && GetLastError() == ERROR_MORE_DATA)) + goto cleanup; /* service start race condition */ ok(ret, "Expected success, got error %lu\n", GetLastError()); ok(needed == 0, "Expected needed buffer to be 0 as we are done\n"); ok(returned == missing, "Expected %lu services to be returned\n", missing); @@ -1797,8 +1792,8 @@ static BOOL test_enum_svc_ex(int attempt) ret = pEnumServicesStatusExW(scm_handle, 0, SERVICE_WIN32, SERVICE_ACTIVE, (BYTE*)exservices, needed, &needed, &returned, NULL, NULL); HeapFree(GetProcessHeap(), 0, exservices); - if (!ret && GetLastError() == ERROR_MORE_DATA && attempt) - goto retry; /* service start race condition */ + if (attempt_retry(!ret && GetLastError() == ERROR_MORE_DATA)) + goto cleanup; /* service start race condition */
servicecountactive = returned;
@@ -1809,8 +1804,8 @@ static BOOL test_enum_svc_ex(int attempt) ret = pEnumServicesStatusExW(scm_handle, 0, SERVICE_WIN32, SERVICE_INACTIVE, (BYTE*)exservices, needed, &needed, &returned, NULL, NULL); HeapFree(GetProcessHeap(), 0, exservices); - if (!ret && GetLastError() == ERROR_MORE_DATA && attempt) - goto retry; /* service start race condition */ + if (attempt_retry(!ret && GetLastError() == ERROR_MORE_DATA)) + goto cleanup; /* service start race condition */
servicecountinactive = returned;
@@ -1821,12 +1816,12 @@ static BOOL test_enum_svc_ex(int attempt) ret = pEnumServicesStatusExW(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, (BYTE*)exservices, needed, &needed, &returned, NULL, NULL); HeapFree(GetProcessHeap(), 0, exservices); - if (!ret && GetLastError() == ERROR_MORE_DATA && attempt) - goto retry; /* service start race condition */ + if (attempt_retry(!ret && GetLastError() == ERROR_MORE_DATA)) + goto cleanup; /* service start race condition */
/* Check if total is the same as active and inactive win32 services */ - if (returned != servicecountactive + servicecountinactive && attempt) - goto retry; /* service start|stop race condition */ + if (attempt_retry(returned != servicecountactive + servicecountinactive)) + goto cleanup; /* service start|stop race condition */ ok(returned == servicecountactive + servicecountinactive, "Expected service count %ld == %ld + %ld\n", returned, servicecountactive, servicecountinactive); @@ -1838,8 +1833,8 @@ static BOOL test_enum_svc_ex(int attempt) exservices = HeapAlloc(GetProcessHeap(), 0, needed); ret = pEnumServicesStatusExW(scm_handle, 0, SERVICE_WIN32 | SERVICE_DRIVER, SERVICE_STATE_ALL, (BYTE*)exservices, needed, &needed, &returned, NULL, NULL); - if (!ret && GetLastError() == ERROR_MORE_DATA && attempt) - goto retry; /* service start race condition */ + if (attempt_retry(!ret && GetLastError() == ERROR_MORE_DATA)) + goto cleanup; /* service start race condition */ ok(ret, "Expected success %lu\n", GetLastError());
/* Loop through all those returned drivers and services */ @@ -1908,16 +1903,13 @@ static BOOL test_enum_svc_ex(int attempt) } HeapFree(GetProcessHeap(), 0, exservices);
- if ((servicecountactive || servicecountinactive) && attempt) - goto retry; /* service start|stop race condition */ + if (attempt_retry(servicecountactive || servicecountinactive)) + goto cleanup; /* service start|stop race condition */ ok(servicecountactive == 0, "Active services mismatch %lu\n", servicecountactive); ok(servicecountinactive == 0, "Inactive services mismatch %lu\n", servicecountinactive);
- alldone = TRUE; - -retry: +cleanup: CloseServiceHandle(scm_handle); - return alldone; }
static void test_close(void) @@ -2999,7 +2991,6 @@ START_TEST(service) SC_HANDLE scm_handle; int myARGC; char** myARGV; - int attempt;
myARGC = winetest_get_mainargs(&myARGV); GetFullPathNameA(myARGV[0], sizeof(selfname), selfname, NULL); @@ -3034,10 +3025,8 @@ START_TEST(service) /* Services may start or stop between enumeration calls, leading to * inconsistencies and failures. So we may need a couple attempts. */ - for (attempt = 2; attempt >= 0; attempt--) - if (test_enum_svc(attempt)) break; - for (attempt = 2; attempt >= 0; attempt--) - if (test_enum_svc_ex(attempt)) break; + LOOP_ON_FLAKY_WINDOWS_TESTS(3) test_enum_svc(); + LOOP_ON_FLAKY_WINDOWS_TESTS(3) test_enum_svc_ex();
test_close(); test_wow64();
From: Francois Gouget fgouget@codeweavers.com
Internet Explorer may create a network session for its own purposes (particularly when it starts), thus changing the session count during the test.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54866 --- dlls/ieframe/tests/webbrowser.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/dlls/ieframe/tests/webbrowser.c b/dlls/ieframe/tests/webbrowser.c index 15ce0272654..adb43f481f6 100644 --- a/dlls/ieframe/tests/webbrowser.c +++ b/dlls/ieframe/tests/webbrowser.c @@ -4436,20 +4436,24 @@ static void test_SetQueryNetSessionCount(void) { LONG count, init_count;
- init_count = pSetQueryNetSessionCount(SESSION_QUERY); - trace("init_count %ld\n", init_count); + /* IE may create a network session for its own purposes during the test */ + LOOP_ON_FLAKY_WINDOWS_TESTS(3) + { + init_count = pSetQueryNetSessionCount(SESSION_QUERY); + trace("init_count %ld\n", init_count);
- count = pSetQueryNetSessionCount(SESSION_INCREMENT); - ok(count == init_count + 1, "count = %ld\n", count); + count = pSetQueryNetSessionCount(SESSION_INCREMENT); + tryok(count == init_count + 1, "count = %ld\n", count);
- count = pSetQueryNetSessionCount(SESSION_QUERY); - ok(count == init_count + 1, "count = %ld\n", count); + count = pSetQueryNetSessionCount(SESSION_QUERY); + tryok(count == init_count + 1, "count = %ld\n", count);
- count = pSetQueryNetSessionCount(SESSION_DECREMENT); - ok(count == init_count, "count = %ld\n", count); + count = pSetQueryNetSessionCount(SESSION_DECREMENT); + tryok(count == init_count, "count = %ld\n", count);
- count = pSetQueryNetSessionCount(SESSION_QUERY); - ok(count == init_count, "count = %ld\n", count); + count = pSetQueryNetSessionCount(SESSION_QUERY); + tryok(count == init_count, "count = %ld\n", count); + } }
static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
v5: * tryok() no longer fails when called outside LOOP_ON_FLAKY_TESTS(). Instead it behaves like a regular ok() call. This is so one can use tryok() in a helper function that can be called either from a flaky loop or outside it: LOOP_ON_FLAKY_TESTS(5) check_something(TRUE); // this case is flaky check_something(FALSE); // but not this one * Only kept a small subset of the tests tryok() can be used in to keep things simple and focused. * Removed the debug traces and code for testing the tryok() mechanism. * Tweaked the test.h comments some more.
On Wed Aug 16 08:25:48 2023 +0000, Jacek Caban wrote:
I think that ieframe doesn't need this mechanism, it would be better to just adjust the test. I created !3577 for that. I also hope that we could do better in other tests. For example, ntdll tests could have a loop in the beginning of `test_file_full_size_information` that would keep querying until sizes match. I'm generally skeptical that we need such a global mechanism.
* I don't think MR!3577 really fixes the ieframe:webbrowser race condition. * Looping at the beginning of test_file_full_size_information() sounds like manually reimplementing this mechanism. I don't see how it is better to have a dozen different implementations instead of a single one that everyone understands.
Also there are quite a few tests that need this mechanism so I think it's better to have a general solution rather than ad-hoc ones everywhere.
On Wed Aug 16 13:28:54 2023 +0000, Zebediah Figura wrote:
FWIW, the quartz tests are really just a deadlock in Wine. It's solvable but it's not simple to solve. I really just need to be able to take the time to design and fix it properly.
I think that means they should not be marked as flaky then.