diff --git a/Source/Tests/ExcelDna.RuntimeTests/NativeAOTOutOfProcess.cs b/Source/Tests/ExcelDna.RuntimeTests/NativeAOTOutOfProcess.cs index cd5285b3..57818338 100644 --- a/Source/Tests/ExcelDna.RuntimeTests/NativeAOTOutOfProcess.cs +++ b/Source/Tests/ExcelDna.RuntimeTests/NativeAOTOutOfProcess.cs @@ -11,6 +11,7 @@ public class NativeAOTOutOfProcess [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTestsAOT)] public void AsyncTask() { + Runner.ExecuteWithRetryWhenExcelBusy(() => { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1"]; functionRange.Formula = "=NativeAsyncTaskHello(\"world\", 200)"; @@ -18,12 +19,13 @@ public void AsyncTask() Automation.WaitFor(() => functionRange.Value?.ToString() == "Hello native async task world", 1000); Assert.Equal("Hello native async task world", functionRange.Value.ToString()); - } + }); } [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTestsAOT)] public void AsyncSleep() { + Runner.ExecuteWithRetryWhenExcelBusy(() => { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1"]; functionRange.Formula = "=NativeAsyncHello(\"world\", 0)"; @@ -31,7 +33,9 @@ public void AsyncSleep() Automation.WaitFor(() => functionRange.Value?.ToString() == "Hello native async world", 1000); Assert.Equal("Hello native async world", functionRange.Value.ToString()); - } + }); + + Runner.ExecuteWithRetryWhenExcelBusy(() => { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["C1"]; functionRange.Formula = "=NativeAsyncHello(\"world\", 200)"; @@ -39,12 +43,13 @@ public void AsyncSleep() Automation.WaitFor(() => functionRange.Value?.ToString() == "Hello native async world", 2000); Assert.Equal("Hello native async world", functionRange.Value.ToString()); - } + }); } [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTestsAOT)] public void DynamicApplication() { + Runner.ExecuteWithRetryWhenExcelBusy(() => { Range functionRange1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["E1"]; @@ -53,7 +58,7 @@ public void DynamicApplication() Assert.Equal(-4152, functionRange2.Value); Assert.Equal(-4152, (int)functionRange1.HorizontalAlignment); - } + }); } } } diff --git a/Source/Tests/ExcelDna.RuntimeTests/ObjectHandleOutOfProcess.cs b/Source/Tests/ExcelDna.RuntimeTests/ObjectHandleOutOfProcess.cs index 38c3c6ea..4dda675c 100644 --- a/Source/Tests/ExcelDna.RuntimeTests/ObjectHandleOutOfProcess.cs +++ b/Source/Tests/ExcelDna.RuntimeTests/ObjectHandleOutOfProcess.cs @@ -11,28 +11,32 @@ public class ObjectHandleOutOfProcess [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void ThreadSafe() { - for (int i = 1; i <= 5; ++i) + Runner.ExecuteWithRetryWhenExcelBusy(() => { + for (int i = 1; i <= 5; ++i) { - Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range[$"C{i}"]; - functionRange.Formula = $"=MyCreateCalcTS({(i - 1) * 20}, 0)"; + { + Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range[$"C{i}"]; + functionRange.Formula = $"=MyCreateCalcTS({(i - 1) * 20}, 0)"; + } + { + Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range[$"D{i}"]; + functionRange.Formula = $"=MyCalcSumTS(C{i})"; + } } + + for (int i = 1; i <= 5; ++i) { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range[$"D{i}"]; - functionRange.Formula = $"=MyCalcSumTS(C{i})"; + Assert.Equal($"{(i - 1) * 20}", functionRange.Value.ToString()); } - } - - for (int i = 1; i <= 5; ++i) - { - Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range[$"D{i}"]; - Assert.Equal($"{(i - 1) * 20}", functionRange.Value.ToString()); - } + }); } [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void Disposable() { + Runner.ExecuteWithRetryWhenExcelBusy(() => { Range functionRangeC1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["C1"]; functionRangeC1.Formula = "=MyGetCreatedDisposableObjectsCount()"; @@ -51,8 +55,9 @@ public void Disposable() Assert.Equal(1, finalCreatedObjectsCount - initialCreatedObjectsCount); Assert.Equal("1", functionRange2.Value.ToString()); - } + }); + Runner.ExecuteWithRetryWhenExcelBusy(() => { Range functionRange1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["C1"]; functionRange1.Formula = "=MyCreateDisposableObject(5)"; @@ -61,8 +66,9 @@ public void Disposable() functionRange2.Formula = "=MyGetDisposableObjectsCount()"; Assert.Equal("2", functionRange2.Value.ToString()); - } + }); + Runner.ExecuteWithRetryWhenExcelBusy(() => { Range functionRange1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1"]; functionRange1.Clear(); @@ -72,37 +78,40 @@ public void Disposable() functionRange2.Formula = "=MyGetDisposableObjectsCount()"; Assert.Equal("1", functionRange2.Value.ToString()); - } + }); } [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void TaskObjectStableCreate() { - string v1; + Runner.ExecuteWithRetryWhenExcelBusy(() => { - Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["A1"]; - functionRange.Formula = $"=MyTaskCreateCalc(100, 1, 2)"; + string v1; { - Range functionRange2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["A2"]; - functionRange2.Formula = $"=MyCalcSum(A1)"; - Automation.WaitFor(() => functionRange2.Value?.ToString() == "3", 3000); - Assert.Equal("3", functionRange2.Value.ToString()); + Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["A1"]; + functionRange.Formula = $"=MyTaskCreateCalc(100, 1, 2)"; + { + Range functionRange2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["A2"]; + functionRange2.Formula = $"=MyCalcSum(A1)"; + Automation.WaitFor(() => functionRange2.Value?.ToString() == "3", 3000); + Assert.Equal("3", functionRange2.Value.ToString()); + } + v1 = functionRange.Value.ToString(); } - v1 = functionRange.Value.ToString(); - } - { - Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1"]; - functionRange.Formula = $"=MyTaskCreateCalc(100, 1, 2)"; { - Range functionRange2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B2"]; - functionRange2.Formula = $"=MyCalcSum(B1)"; - Automation.WaitFor(() => functionRange2.Value?.ToString() == "3", 3000); - Assert.Equal("3", functionRange2.Value.ToString()); + Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1"]; + functionRange.Formula = $"=MyTaskCreateCalc(100, 1, 2)"; + { + Range functionRange2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B2"]; + functionRange2.Formula = $"=MyCalcSum(B1)"; + Automation.WaitFor(() => functionRange2.Value?.ToString() == "3", 3000); + Assert.Equal("3", functionRange2.Value.ToString()); + } + string v2 = functionRange.Value.ToString(); + Assert.Equal(v1, v2); } - string v2 = functionRange.Value.ToString(); - Assert.Equal(v1, v2); - } + }); } [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] @@ -110,48 +119,52 @@ public void TaskDisposable() { foreach (int delay in new[] { 0, 500 }) { + int x = 0; + Runner.ExecuteWithRetryWhenExcelBusy(() => { - Range functionRangeC1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["C1"]; - functionRangeC1.Formula = "=MyGetCreatedDisposableObjectsCount()"; - int initialCreatedObjectsCount = (int)functionRangeC1.Value; + { + Range functionRangeC1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["C1"]; + functionRangeC1.Formula = "=MyGetCreatedDisposableObjectsCount()"; + int initialCreatedObjectsCount = (int)functionRangeC1.Value; - Range functionRange1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1"]; - functionRange1.Formula = $"=MyTaskCreateDisposableObject({delay}, 1)"; - Automation.WaitFor(() => functionRange1.Value.ToString().Contains("DisposableObject"), 3000); + Range functionRange1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1"]; + functionRange1.Formula = $"=MyTaskCreateDisposableObject({delay}, {++x})"; + Automation.WaitFor(() => functionRange1.Value.ToString().Contains("DisposableObject"), 3000); - Range functionRange2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B2"]; - functionRange2.Formula = "=MyGetDisposableObjectsCount()"; + Range functionRange2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B2"]; + functionRange2.Formula = "=MyGetDisposableObjectsCount()"; - Range functionRangeC2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["C2"]; - functionRangeC2.Formula = "=MyGetCreatedDisposableObjectsCount()"; - int finalCreatedObjectsCount = (int)functionRangeC2.Value; + Range functionRangeC2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["C2"]; + functionRangeC2.Formula = "=MyGetCreatedDisposableObjectsCount()"; + int finalCreatedObjectsCount = (int)functionRangeC2.Value; - Assert.Equal(1, finalCreatedObjectsCount - initialCreatedObjectsCount); + Assert.Equal(1, finalCreatedObjectsCount - initialCreatedObjectsCount); - Assert.Equal("1", functionRange2.Value.ToString()); - } + Assert.Equal("1", functionRange2.Value.ToString()); + } - { - Range functionRange1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["C1"]; - functionRange1.Formula = $"=MyTaskCreateDisposableObject({delay}, 5)"; - Automation.WaitFor(() => functionRange1.Value.ToString().Contains("DisposableObject"), 3000); + { + Range functionRange1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["C1"]; + functionRange1.Formula = $"=MyTaskCreateDisposableObject({delay}, {++x})"; + Automation.WaitFor(() => functionRange1.Value.ToString().Contains("DisposableObject"), 3000); - Range functionRange2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["C2"]; - functionRange2.Formula = "=MyGetDisposableObjectsCount()"; + Range functionRange2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["C2"]; + functionRange2.Formula = "=MyGetDisposableObjectsCount()"; - Assert.Equal("2", functionRange2.Value.ToString()); - } + Assert.Equal("2", functionRange2.Value.ToString()); + } - { - Range functionRange1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1"]; - functionRange1.Clear(); - Automation.Wait(2000); + { + Range functionRange1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1"]; + functionRange1.Clear(); + Automation.Wait(2000); - Range functionRange2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B2"]; - functionRange2.Formula = "=MyGetDisposableObjectsCount()"; + Range functionRange2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B2"]; + functionRange2.Formula = "=MyGetDisposableObjectsCount()"; - Assert.Equal("1", functionRange2.Value.ToString()); - } + Assert.Equal("1", functionRange2.Value.ToString()); + } + }); } } @@ -160,27 +173,30 @@ public void AsyncObjectCreate() { foreach (int delay in new[] { 0, 500 }) { + Runner.ExecuteWithRetryWhenExcelBusy(() => { - Range functionRange1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["E1"]; - functionRange1.Formula = $"=MyAsyncCreateCalc({delay}, 14, 15)"; - Automation.WaitFor(() => functionRange1.Value.ToString().Contains("Calc"), 3000); + { + Range functionRange1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["E1"]; + functionRange1.Formula = $"=MyAsyncCreateCalc({delay}, 14, 15)"; + Automation.WaitFor(() => functionRange1.Value.ToString().Contains("Calc"), 3000); - Range functionRange2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["E2"]; - functionRange2.Formula = "=MyCalcSum(E1)"; + Range functionRange2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["E2"]; + functionRange2.Formula = "=MyCalcSum(E1)"; - Assert.Equal("29", functionRange2.Value.ToString()); - } + Assert.Equal("29", functionRange2.Value.ToString()); + } - { - Range functionRange1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["F1"]; - functionRange1.Formula = $"=MyAsyncCreateCalcWithCancellation({delay}, 1, 2)"; - Automation.WaitFor(() => functionRange1.Value.ToString().Contains("Calc"), 3000); + { + Range functionRange1 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["F1"]; + functionRange1.Formula = $"=MyAsyncCreateCalcWithCancellation({delay}, 1, 2)"; + Automation.WaitFor(() => functionRange1.Value.ToString().Contains("Calc"), 3000); - Range functionRange2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["F2"]; - functionRange2.Formula = "=MyCalcSum(F1)"; + Range functionRange2 = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["F2"]; + functionRange2.Formula = "=MyCalcSum(F1)"; - Assert.Equal("3", functionRange2.Value.ToString()); - } + Assert.Equal("3", functionRange2.Value.ToString()); + } + }); } } } diff --git a/Source/Tests/ExcelDna.RuntimeTests/RegistrationOutOfProcess.cs b/Source/Tests/ExcelDna.RuntimeTests/RegistrationOutOfProcess.cs index 6420c817..258f2fea 100644 --- a/Source/Tests/ExcelDna.RuntimeTests/RegistrationOutOfProcess.cs +++ b/Source/Tests/ExcelDna.RuntimeTests/RegistrationOutOfProcess.cs @@ -11,6 +11,7 @@ public class RegistrationOutOfProcess [ExcelFact(Workbook = "", AddIn = AddInPath.RuntimeTests)] public void AsyncSleep() { + Runner.ExecuteWithRetryWhenExcelBusy(() => { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1"]; functionRange.Formula = "=MyAsyncHello(\"world\", 0)"; @@ -18,7 +19,9 @@ public void AsyncSleep() Automation.WaitFor(() => functionRange.Value?.ToString() == "Hello async world", 1000); Assert.Equal("Hello async world", functionRange.Value.ToString()); - } + }); + + Runner.ExecuteWithRetryWhenExcelBusy(() => { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["C1"]; functionRange.Formula = "=MyAsyncHello(\"world\", 200)"; @@ -26,7 +29,7 @@ public void AsyncSleep() Automation.WaitFor(() => functionRange.Value?.ToString() == "Hello async world", 2000); Assert.Equal("Hello async world", functionRange.Value.ToString()); - } + }); } } } diff --git a/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleOutOfProcess.cs b/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleOutOfProcess.cs index 2b8d5946..34295a55 100644 --- a/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleOutOfProcess.cs +++ b/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleOutOfProcess.cs @@ -11,6 +11,7 @@ public class RegistrationSampleOutOfProcess [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSample)] public void AsyncSleep() { + Runner.ExecuteWithRetryWhenExcelBusy(() => { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1"]; functionRange.Formula = "=dnaDelayedHello(\"world\", 0)"; @@ -18,7 +19,9 @@ public void AsyncSleep() Automation.WaitFor(() => functionRange.Value?.ToString() == "Hello world!", 1000); Assert.Equal("Hello world!", functionRange.Value.ToString()); - } + }); + + Runner.ExecuteWithRetryWhenExcelBusy(() => { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["C1"]; functionRange.Formula = "=dnaDelayedHello(\"world\", 200)"; @@ -26,17 +29,18 @@ public void AsyncSleep() Automation.WaitFor(() => functionRange.Value?.ToString() == "Hello world!", 2000); Assert.Equal("Hello world!", functionRange.Value.ToString()); - } + }); } [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSample)] public void GettingData() { + Runner.ExecuteWithRetryWhenExcelBusy(() => { Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["B1"]; functionRange.Formula = "=dnaDelayedHelloAsync(\"a\", 2000)"; Assert.Equal(-2146826245, functionRange.Value); - } + }); } } } diff --git a/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleOutOfProcessFS.cs b/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleOutOfProcessFS.cs index afad621e..2e002898 100644 --- a/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleOutOfProcessFS.cs +++ b/Source/Tests/ExcelDna.RuntimeTests/RegistrationSampleOutOfProcessFS.cs @@ -11,6 +11,7 @@ public class RegistrationSampleOutOfProcessFS [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSampleFS)] public void AsyncSleep() { + Runner.ExecuteWithRetryWhenExcelBusy(() => { Range functionRangeA = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["A3"]; functionRangeA.Value = "alice"; @@ -25,7 +26,9 @@ public void AsyncSleep() Automation.WaitFor(() => functionRange.Value?.ToString() == "Hello alice", 3000); Assert.Equal("Hello alice", functionRange.Value.ToString()); - } + }); + + Runner.ExecuteWithRetryWhenExcelBusy(() => { Range functionRangeA = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["A4"]; functionRangeA.Value = "bob"; @@ -40,12 +43,14 @@ public void AsyncSleep() Automation.WaitFor(() => functionRange.Value?.ToString() == "Hello bob", 3000); Assert.Equal("Hello bob", functionRange.Value.ToString()); - } + }); } [ExcelFact(Workbook = "", AddIn = AddInPath.RegistrationSampleFS)] public void Timer() { + bool afterRetry = false; + Runner.ExecuteWithRetryWhenExcelBusy(() => { Range functionRangeE = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["E3"]; functionRangeE.Value = "2000"; @@ -55,14 +60,18 @@ public void Timer() Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["G3"]; functionRange.Formula = "=dnaFsCreateTimer(E3,F3)"; - Assert.Equal(-2146826246, functionRange.Value); // #N/A + if (!afterRetry) + Assert.Equal(-2146826246, functionRange.Value); // #N/A Automation.WaitFor(() => functionRange.Value.GetType() == typeof(double), 3000); double v1 = functionRange.Value; Automation.WaitFor(() => functionRange.Value != v1, 3000); Assert.True(functionRange.Value != v1); - } + }, () => afterRetry = true); + + afterRetry = false; + Runner.ExecuteWithRetryWhenExcelBusy(() => { Range functionRangeE = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["E4"]; functionRangeE.Value = "666"; @@ -72,14 +81,15 @@ public void Timer() Range functionRange = ((Worksheet)ExcelDna.Testing.Util.Workbook.Sheets[1]).Range["G4"]; functionRange.Formula = "=dnaFsCreateTimer(E4,F4)"; - Assert.Equal(-2146826246, functionRange.Value); // #N/A + if (!afterRetry) + Assert.Equal(-2146826246, functionRange.Value); // #N/A Automation.WaitFor(() => functionRange.Value.GetType() == typeof(double), 3000); double v1 = functionRange.Value; Automation.WaitFor(() => functionRange.Value != v1, 3000); Assert.True(functionRange.Value != v1); - } + }, () => afterRetry = true); } } } diff --git a/Source/Tests/ExcelDna.RuntimeTests/Runner.cs b/Source/Tests/ExcelDna.RuntimeTests/Runner.cs new file mode 100644 index 00000000..90df84c6 --- /dev/null +++ b/Source/Tests/ExcelDna.RuntimeTests/Runner.cs @@ -0,0 +1,23 @@ +using System.Runtime.InteropServices; + +namespace ExcelDna.RuntimeTests +{ + internal class Runner + { + public static void ExecuteWithRetryWhenExcelBusy(Action action, Action? retryAction = null) + { + for (int i = 0; i < 3; ++i) + { + try + { + action(); + return; + } + catch (COMException e) when (e.ErrorCode == -2147417846) // 0x8001010A (RPC_E_SERVERCALL_RETRYLATER) + { + retryAction?.Invoke(); + } + } + } + } +}