-
Notifications
You must be signed in to change notification settings - Fork 4.1k
/
Copy pathHelper.cs
173 lines (157 loc) · 6.68 KB
/
Helper.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable disable
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using UIAutomationClient;
namespace Microsoft.VisualStudio.IntegrationTest.Utilities
{
public static class Helper
{
/// <summary>
/// A long timeout used to avoid hangs in tests, where a test failure manifests as an operation never occurring.
/// </summary>
public static readonly TimeSpan HangMitigatingTimeout = TimeSpan.FromMinutes(1);
private static IUIAutomation2 _automation;
public static IUIAutomation2 Automation
{
get
{
if (_automation == null)
{
Interlocked.CompareExchange(ref _automation, new CUIAutomation8(), null);
}
return _automation;
}
}
/// <summary>
/// This method will retry the action represented by the 'action' argument,
/// milliseconds, waiting 'delay' milliseconds after each retry. If a given retry returns a value
/// other than default(T), this value is returned.
/// </summary>
/// <param name="action">the action to retry</param>
/// <param name="delay">the amount of time to wait between retries in milliseconds</param>
/// <typeparam name="T">type of return value</typeparam>
/// <returns>the return value of 'action'</returns>
public static T Retry<T>(Func<T> action, int delay)
=> Retry(action, TimeSpan.FromMilliseconds(delay));
/// <summary>
/// This method will retry the action represented by the 'action' argument,
/// milliseconds, waiting 'delay' milliseconds after each retry and will swallow all exceptions.
/// If a given retry returns a value other than default(T), this value is returned.
/// </summary>
/// <param name="action">the action to retry</param>
/// <param name="delay">the amount of time to wait between retries in milliseconds</param>
/// <typeparam name="T">type of return value</typeparam>
/// <returns>the return value of 'action'</returns>
public static T RetryIgnoringExceptions<T>(Func<T> action, int delay)
=> RetryIgnoringExceptions(action, TimeSpan.FromMilliseconds(delay));
/// <summary>
/// This method will retry the action represented by the 'action' argument,
/// waiting for 'delay' time after each retry. If a given retry returns a value
/// other than default(T), this value is returned.
/// </summary>
/// <param name="action">the action to retry</param>
/// <param name="delay">the amount of time to wait between retries</param>
/// <typeparam name="T">type of return value</typeparam>
/// <returns>the return value of 'action'</returns>
public static T Retry<T>(Func<T> action, TimeSpan delay, int retryCount = -1)
{
return RetryHelper(() =>
{
try
{
return action();
}
catch (COMException)
{
// Devenv can throw COMExceptions if it's busy when we make DTE calls.
return default;
}
},
delay,
retryCount);
}
/// <summary>
/// This method will retry the asynchronous action represented by <paramref name="action"/>,
/// waiting for <paramref name="delay"/> time after each retry. If a given retry returns a value
/// other than the default value of <typeparamref name="T"/>, this value is returned.
/// </summary>
/// <param name="action">the asynchronous action to retry</param>
/// <param name="delay">the amount of time to wait between retries</param>
/// <typeparam name="T">type of return value</typeparam>
/// <returns>the return value of <paramref name="action"/></returns>
public static Task<T> RetryAsync<T>(Func<Task<T>> action, TimeSpan delay)
{
return RetryAsyncHelper(async () =>
{
try
{
return await action();
}
catch (COMException)
{
// Devenv can throw COMExceptions if it's busy when we make DTE calls.
return default;
}
},
delay);
}
/// <summary>
/// This method will retry the action represented by the 'action' argument,
/// milliseconds, waiting 'delay' milliseconds after each retry and will swallow all exceptions.
/// If a given retry returns a value other than default(T), this value is returned.
/// </summary>
/// <param name="action">the action to retry</param>
/// <param name="delay">the amount of time to wait between retries in milliseconds</param>
/// <typeparam name="T">type of return value</typeparam>
/// <returns>the return value of 'action'</returns>
public static T RetryIgnoringExceptions<T>(Func<T> action, TimeSpan delay, int retryCount = -1)
{
return RetryHelper(() =>
{
try
{
return action();
}
catch (Exception)
{
return default;
}
},
delay,
retryCount);
}
private static T RetryHelper<T>(Func<T> action, TimeSpan delay, int retryCount)
{
for (var i = 0; true; i++)
{
var retval = action();
if (i == retryCount)
{
return retval;
}
if (!Equals(default(T), retval))
{
return retval;
}
System.Threading.Thread.Sleep(delay);
}
}
private static async Task<T> RetryAsyncHelper<T>(Func<Task<T>> action, TimeSpan delay)
{
while (true)
{
var retval = await action().ConfigureAwait(true);
if (!Equals(default(T), retval))
{
return retval;
}
await Task.Delay(delay).ConfigureAwait(true);
}
}
}
}