Work around XUnit FileLoadException issues (dotnet/coreclr#20644)
authorEgor Chesakov <Egor.Chesakov@microsoft.com>
Wed, 31 Oct 2018 16:28:09 +0000 (09:28 -0700)
committerGitHub <noreply@github.com>
Wed, 31 Oct 2018 16:28:09 +0000 (09:28 -0700)
In order to mitigate System.IO.FileLoadException we built our own xunit.console.dll with ConcurrentDictionary used for DependencyContextAssemblyCache.managedAssemblyCache instead of Dictionary and use this instead of the one pulled from NuGet.

Commit migrated from https://github.com/dotnet/coreclr/commit/4bcbb70ea3b20b959c50eb7132783ead33e2e1e9

src/coreclr/tests/runtest.py

index a90a0ea..d1b4683 100755 (executable)
@@ -52,12 +52,20 @@ import tempfile
 import time
 import re
 import string
+import zipfile
 
 import xml.etree.ElementTree
 
 from collections import defaultdict
 from sys import platform as _platform
 
+# Version specific imports
+
+if sys.version_info.major < 3:
+    import urllib
+else:
+    import urllib.request
+
 ################################################################################
 # Argument Parser
 ################################################################################
@@ -764,6 +772,52 @@ def run_tests(host_os,
     if test_env is not None:
         os.environ["__TestEnv"] = test_env
 
+    #=====================================================================================================================================================
+    #
+    # This is a workaround needed to unblock our CI (in particular, Linux/arm and Linux/arm64 jobs) from the following failures appearing almost in every
+    # pull request (but hard to reproduce locally)
+    #
+    #   System.IO.FileLoadException: Could not load file or assembly 'Exceptions.Finalization.XUnitWrapper, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
+    #   An operation is not legal in the current state. (Exception from HRESULT: 0x80131509 (COR_E_INVALIDOPERATION))
+    #
+    # COR_E_INVALIDOPERATION comes from System.InvalidOperationException that is thrown during AssemblyLoadContext.ResolveUsingResolvingEvent
+    # when multiple threads attempt to modify an instance of Dictionary (managedAssemblyCache) during Xunit.DependencyContextAssemblyCache.LoadManagedDll call.
+    #
+    # In order to mitigate the failure we built our own xunit.console.dll with ConcurrentDictionary used for managedAssemblyCache and use this instead of
+    # the one pulled from NuGet. The exact code that got built can be found at the following fork of Xunit
+    #  * https://github.com/echesakovMSFT/xunit/tree/UseConcurrentDictionaryInDependencyContextAssemblyCache
+    #
+    # The assembly was built using Microsoft Visual Studio v15.9.0-pre.4.0 Developer Command Prompt using the following commands
+    #  1) git clone https://github.com/echesakovMSFT/xunit.git --branch UseConcurrentDictionaryInDependencyContextAssemblyCache --single-branch
+    #  2) cd xunit
+    #  3) git submodule update --init
+    #  4) powershell .\build.ps1
+    #
+    # Then file "xunit\src\xunit.console\bin\Release\netcoreapp2.0\xunit.console.dll" was archived and uploaded to the clrjit blob storage.
+    #
+    # Ideally, this code should be removed when we find a more robust way of running Xunit tests.
+    #
+    # References:
+    #  * https://github.com/dotnet/coreclr/issues/20392
+    #  * https://github.com/dotnet/coreclr/issues/20594
+    #  * https://github.com/xunit/xunit/issues/1842
+    #  * https://github.com/xunit/xunit/pull/1846
+    #
+    #=====================================================================================================================================================
+
+    print("Download and overwrite xunit.console.dll in Core_Root")
+
+    urlretrieve = urllib.urlretrieve if sys.version_info.major < 3 else urllib.request.urlretrieve
+    zipfilename = os.path.join(tempfile.gettempdir(), "xunit.console.dll.zip")
+    url = r"https://clrjit.blob.core.windows.net/xunit-console/xunit.console.dll.zip"
+    urlretrieve(url, zipfilename)
+
+    with zipfile.ZipFile(zipfilename,"r") as ziparch:
+        ziparch.extractall(core_root)
+
+    os.remove(zipfilename)
+    assert not os.path.isfile(zipfilename)
+
     # Call msbuild.
     return call_msbuild(coreclr_repo_location,
                         dotnetcli_location,