Skip to content

Commit

Permalink
[RISC-V] Fix System.Net.Sockets.Tests on Qemu
Browse files Browse the repository at this point in the history
Before this change there are 8 failures from System.Net.Sockets.Tests with following reports:

root@69fa7050f168:/runtime/artifacts/bin/System.Net.Sockets.Tests/Release/net9.0-unix# /runtime/artifacts/bin/testhost/net9.0-linux-Release-riscv64/dotnet  exec --runtimeconfig System.Net.Sockets.Tests.runtimeconfig.json --depsfile  System.Net.Sockets.Tests.deps.json  xunit.console.dll System.Net.Sockets.Tests.dll -xml testResults.xml -nologo -notrait category=nonnetcoreapptests -notrait category=nonlinuxtests -notrait category=failing -maxthreads 32
  Discovering: System.Net.Sockets.Tests (method display = ClassAndMethod, method display options = None)
  Discovered:  System.Net.Sockets.Tests (found 1672 of 1820 test cases)
  Starting:    System.Net.Sockets.Tests (parallel test collections = on [32 threads], stop on fail = off)
    System.Net.Sockets.Tests.CreateSocket.Ctor_Raw_NotSupported_ExpectedError [SKIP]
      Condition(s) not met: "NotSupportsRawSockets"
    System.Net.Sockets.Tests.KeepAliveTest.Socket_Get_KeepAlive_Time_AsByteArray_OptionLengthZero_Failure [FAIL]
      System.Net.Sockets.SocketException : Bad address
      Stack Trace:
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3737,0): at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, Boolean disconnectOnFailure, String callerName)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3728,0): at System.Net.Sockets.Socket.UpdateStatusAfterSocketOptionErrorAndThrowException(SocketError error, String callerName)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(2145,0): at System.Net.Sockets.Socket.GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, Int32 optionLength)
        /home/d.jurczak2/runtime/src/libraries/System.Net.Sockets/tests/FunctionalTests/KeepAliveTest.cs(136,0): at System.Net.Sockets.Tests.KeepAliveTest.Socket_Get_KeepAlive_Time_AsByteArray_OptionLengthZero_Failure()

           at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
        /runtime/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.cs(57,0): at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
    System.Net.Sockets.Tests.ArgumentValidation.Connect_ConnectTwice_NotSupported(invalidatingAction: 1) [FAIL]
      System.Net.Sockets.SocketException : Protocol not available
      Stack Trace:
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3737,0): at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, Boolean disconnectOnFailure, String callerName)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3728,0): at System.Net.Sockets.Socket.UpdateStatusAfterSocketOptionErrorAndThrowException(SocketError error, String callerName)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3466,0): at System.Net.Sockets.Socket.SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, Int32 optionValue, Boolean silent)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(1966,0): at System.Net.Sockets.Socket.SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, Int32 optionValue)
        /home/d.jurczak2/runtime/src/libraries/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs(809,0): at System.Net.Sockets.Tests.ArgumentValidation.Connect_ConnectTwice_NotSupported(Int32 invalidatingAction)
           at InvokeStub_ArgumentValidation.Connect_ConnectTwice_NotSupported(Object, Span`1)
           at System.Reflection.MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
    System.Net.Sockets.Tests.SocketOptionNameTest.MulticastInterface_Set_AnyInterface_Succeeds [FAIL]
      System.Net.Sockets.SocketException : Unknown socket error
      Stack Trace:
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3737,0): at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, Boolean disconnectOnFailure, String callerName)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3728,0): at System.Net.Sockets.Socket.UpdateStatusAfterSocketOptionErrorAndThrowException(SocketError error, String callerName)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3479,0): at System.Net.Sockets.Socket.SetMulticastOption(SocketOptionName optionName, MulticastOption MR)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(2021,0): at System.Net.Sockets.Socket.SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, Object optionValue)
        /home/d.jurczak2/runtime/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketOptionNameTest.cs(96,0): at System.Net.Sockets.Tests.SocketOptionNameTest.MulticastInterface_Set_Helper(Int32 interfaceIndex)
        /home/d.jurczak2/runtime/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketOptionNameTest.cs(71,0): at System.Net.Sockets.Tests.SocketOptionNameTest.MulticastInterface_Set_AnyInterface_Succeeds()
        --- End of stack trace from previous location ---
    System.Net.Sockets.Tests.KeepAliveTest.Socket_Get_KeepAlive_Time_AsByteArray_BufferNullOrTooSmall_Failure(buffer: null) [FAIL]
      System.Net.Sockets.SocketException : Bad address
      Stack Trace:
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3737,0): at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, Boolean disconnectOnFailure, String callerName)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3728,0): at System.Net.Sockets.Socket.UpdateStatusAfterSocketOptionErrorAndThrowException(SocketError error, String callerName)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(2121,0): at System.Net.Sockets.Socket.GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, Byte[] optionValue)
        /home/d.jurczak2/runtime/src/libraries/System.Net.Sockets/tests/FunctionalTests/KeepAliveTest.cs(156,0): at System.Net.Sockets.Tests.KeepAliveTest.Socket_Get_KeepAlive_Time_AsByteArray_BufferNullOrTooSmall_Failure(Byte[] buffer)

           at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
        /runtime/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.cs(178,0): at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
    System.Net.Sockets.Tests.KeepAliveTest.Socket_Get_KeepAlive_Time_AsByteArray_BufferNullOrTooSmall_Failure(buffer: []) [FAIL]
      System.Net.Sockets.SocketException : Bad address
      Stack Trace:
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3737,0): at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, Boolean disconnectOnFailure, String callerName)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3728,0): at System.Net.Sockets.Socket.UpdateStatusAfterSocketOptionErrorAndThrowException(SocketError error, String callerName)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(2121,0): at System.Net.Sockets.Socket.GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, Byte[] optionValue)
        /home/d.jurczak2/runtime/src/libraries/System.Net.Sockets/tests/FunctionalTests/KeepAliveTest.cs(156,0): at System.Net.Sockets.Tests.KeepAliveTest.Socket_Get_KeepAlive_Time_AsByteArray_BufferNullOrTooSmall_Failure(Byte[] buffer)
           at InvokeStub_KeepAliveTest.Socket_Get_KeepAlive_Time_AsByteArray_BufferNullOrTooSmall_Failure(Object, Span`1)
           at System.Reflection.MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
    System.Net.Sockets.Tests.SocketOptionNameTest.MulticastOption_CreateSocketSetGetOption_GroupAndInterfaceIndex_SetSucceeds_GetThrows [FAIL]
      System.Net.Sockets.SocketException : Unknown socket error
      Stack Trace:
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3737,0): at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, Boolean disconnectOnFailure, String callerName)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3728,0): at System.Net.Sockets.Socket.UpdateStatusAfterSocketOptionErrorAndThrowException(SocketError error, String callerName)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3479,0): at System.Net.Sockets.Socket.SetMulticastOption(SocketOptionName optionName, MulticastOption MR)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(2021,0): at System.Net.Sockets.Socket.SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, Object optionValue)
        /home/d.jurczak2/runtime/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketOptionNameTest.cs(61,0): at System.Net.Sockets.Tests.SocketOptionNameTest.MulticastOption_CreateSocketSetGetOption_GroupAndInterfaceIndex_SetSucceeds_GetThrows()

           at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
        /runtime/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.cs(57,0): at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
    System.Net.Sockets.Tests.SocketOptionNameTest.MulticastInterface_Set_IPv6_AnyInterface_Succeeds [FAIL]
      System.Net.Sockets.SocketException : Protocol not available
      Stack Trace:
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3737,0): at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, Boolean disconnectOnFailure, String callerName)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3728,0): at System.Net.Sockets.Socket.UpdateStatusAfterSocketOptionErrorAndThrowException(SocketError error, String callerName)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3466,0): at System.Net.Sockets.Socket.SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, Int32 optionValue, Boolean silent)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(1966,0): at System.Net.Sockets.Socket.SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, Int32 optionValue)
        /home/d.jurczak2/runtime/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketOptionNameTest.cs(199,0): at System.Net.Sockets.Tests.SocketOptionNameTest.MulticastInterface_Set_IPv6_Helper(Int32 interfaceIndex)
        /home/d.jurczak2/runtime/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketOptionNameTest.cs(129,0): at System.Net.Sockets.Tests.SocketOptionNameTest.MulticastInterface_Set_IPv6_AnyInterface_Succeeds()
        --- End of stack trace from previous location ---
    System.Net.Sockets.Tests.ArgumentValidation.ConnectAsync_ConnectTwice_NotSupported(invalidatingAction: 1) [FAIL]
      System.Net.Sockets.SocketException : Protocol not available
      Stack Trace:
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3737,0): at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, Boolean disconnectOnFailure, String callerName)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3728,0): at System.Net.Sockets.Socket.UpdateStatusAfterSocketOptionErrorAndThrowException(SocketError error, String callerName)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(3466,0): at System.Net.Sockets.Socket.SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, Int32 optionValue, Boolean silent)
        /runtime/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs(1966,0): at System.Net.Sockets.Socket.SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, Int32 optionValue)
        /home/d.jurczak2/runtime/src/libraries/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs(842,0): at System.Net.Sockets.Tests.ArgumentValidation.ConnectAsync_ConnectTwice_NotSupported(Int32 invalidatingAction)
           at InvokeStub_ArgumentValidation.ConnectAsync_ConnectTwice_NotSupported(Object, Span`1)
           at System.Reflection.MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
  Finished:    System.Net.Sockets.Tests
=== TEST EXECUTION SUMMARY ===
   System.Net.Sockets.Tests  Total: 2874, Errors: 0, Failed: 8, Skipped: 1, Time: 139.280s

Those failures are caused by Qemu's buggy and/or implementation defined behavior like:
https://gitlab.com/qemu-project/qemu/-/issues/2410
https://gitlab.com/qemu-project/qemu/-/issues/2390
https://gitlab.com/qemu-project/qemu/-/issues/1837

In this patch we add couple of workarounds to make all System.Net.Sockets.Tests passing.
  • Loading branch information
yurai007 committed Jun 27, 2024
1 parent 8909110 commit dd886c7
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public static partial class PlatformDetection

public static bool IsMonoLinuxArm64 => IsMonoRuntime && IsLinux && IsArm64Process;
public static bool IsNotMonoLinuxArm64 => !IsMonoLinuxArm64;
public static bool IsNotRiscV64Ubuntu => !IsUbuntu || !IsRiscV64Process;

// OSX family
public static bool IsApplePlatform => IsOSX || IsiOS || IstvOS || IsMacCatalyst;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -794,18 +794,20 @@ await Task.WhenAll(

[Theory]
[PlatformSpecific(TestPlatforms.AnyUnix)] // API throws PNSE on Unix
[InlineData(0)]
[InlineData(1)]
public void Connect_ConnectTwice_NotSupported(int invalidatingAction)
[InlineData(false)]
[InlineData(true)]
public void Connect_ConnectTwice_NotSupported(bool invalidatingAction)
{
using (Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
switch (invalidatingAction)
// On RISC-V Qemu we omit one test case due to: https://gitlab.com/qemu-project/qemu/-/issues/2410
bool invalidatingActionOnPlatform = invalidatingAction && PlatformDetection.IsNotRiscV64Ubuntu;
switch (invalidatingActionOnPlatform)
{
case 0:
case false:
IntPtr handle = client.Handle; // exposing the underlying handle
break;
case 1:
case true:
client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.Debug, 1); // untracked socket option
break;
}
Expand All @@ -825,20 +827,22 @@ public void Connect_ConnectTwice_NotSupported(int invalidatingAction)

[Theory]
[PlatformSpecific(TestPlatforms.AnyUnix)] // API throws PNSE on Unix
[InlineData(0)]
[InlineData(1)]
public void ConnectAsync_ConnectTwice_NotSupported(int invalidatingAction)
[InlineData(false)]
[InlineData(true)]
public void ConnectAsync_ConnectTwice_NotSupported(bool invalidatingAction)
{
AutoResetEvent completed = new AutoResetEvent(false);

using (Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
switch (invalidatingAction)
// On RISC-V Qemu we omit one test case due to: https://gitlab.com/qemu-project/qemu/-/issues/2410
bool invalidatingActionOnPlatform = invalidatingAction && PlatformDetection.IsNotRiscV64Ubuntu;
switch (invalidatingActionOnPlatform)
{
case 0:
case false:
IntPtr handle = client.Handle; // exposing the underlying handle
break;
case 1:
case true:
client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.Debug, 1); // untracked socket option
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ namespace System.Net.Sockets.Tests
public partial class SocketOptionNameTest
{
private static bool SocketsReuseUnicastPortSupport => Capability.SocketsReuseUnicastPortSupport().HasValue;
private static bool SupportedOnPlatform = PlatformDetection.IsNotWindowsNanoNorServerCore && PlatformDetection.IsNotRiscV64Ubuntu;

[ConditionalFact(nameof(SocketsReuseUnicastPortSupport))]
public void ReuseUnicastPort_CreateSocketGetOption()
Expand Down Expand Up @@ -50,7 +51,7 @@ public void ReuseUnicastPort_CreateSocketSetOption()
}
}

[Fact]
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotRiscV64Ubuntu))]
public void MulticastOption_CreateSocketSetGetOption_GroupAndInterfaceIndex_SetSucceeds_GetThrows()
{
int interfaceIndex = 0;
Expand All @@ -64,7 +65,7 @@ public void MulticastOption_CreateSocketSetGetOption_GroupAndInterfaceIndex_SetS
}
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoNorServerCore))] // Skip on Nano: https://github.com/dotnet/runtime/issues/26286
[ConditionalFact(nameof(SupportedOnPlatform))] // Skip on Nano: https://github.com/dotnet/runtime/issues/26286 and RISC-V Qemu
public async Task MulticastInterface_Set_AnyInterface_Succeeds()
{
// On all platforms, index 0 means "any interface"
Expand Down Expand Up @@ -120,7 +121,7 @@ public void MulticastInterface_Set_InvalidIndex_Throws()
}
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoNorServerCore))] // Skip on Nano: https://github.com/dotnet/runtime/issues/26286
[ConditionalFact(nameof(SupportedOnPlatform))] // Skip on Nano: https://github.com/dotnet/runtime/issues/26286 and RISC-V Qemu
[SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.FreeBSD, "Expected behavior is different on OSX or FreeBSD")]
[ActiveIssue("https://github.com/dotnet/runtime/issues/52124", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
public async Task MulticastInterface_Set_IPv6_AnyInterface_Succeeds()
Expand Down
10 changes: 9 additions & 1 deletion src/native/libs/System.Native/pal_networking.c
Original file line number Diff line number Diff line change
Expand Up @@ -2088,7 +2088,15 @@ int32_t SystemNative_GetSockOpt(
{
return Error_EFAULT;
}

#if defined(TARGET_RISCV64)
uint8_t nonEmptyOptionValueBuffer;
if (socketOptionLevel == SocketOptionLevel_SOL_TCP && socketOptionName == SocketOptionName_SO_TCP_KEEPALIVE_TIME && optionValue == NULL
&& *optionLen == 0)
{
// It's workaround for Qemu bug: https://gitlab.com/qemu-project/qemu/-/issues/2390.
optionValue = &nonEmptyOptionValueBuffer;
}
#endif
int fd = ToFileDescriptor(socket);

//
Expand Down

0 comments on commit dd886c7

Please sign in to comment.