diff --git a/src/Build.UnitTests/BackEnd/UnixNodeReuseFixes_Tests.cs b/src/Build.UnitTests/BackEnd/UnixNodeReuseFixes_Tests.cs new file mode 100644 index 00000000000..5e098a01fc4 --- /dev/null +++ b/src/Build.UnitTests/BackEnd/UnixNodeReuseFixes_Tests.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if NET + +using Microsoft.Build.Internal; +using Microsoft.Build.Shared; +using Shouldly; +using Xunit; + +namespace Microsoft.Build.UnitTests +{ + /// + /// Tests for Unix node reuse bug fixes: + /// - SessionId = 0 on Unix (cross-terminal node reuse) + /// + public class UnixNodeReuseFixes_Tests + { + [UnixOnlyFact] + public void Handshake_OnUnix_SessionIdIsZero() + { + var handshake = new Handshake(HandshakeOptions.NodeReuse); + + // Use the structured accessor rather than parsing the key string + handshake.RetrieveHandshakeComponents().SessionId.ShouldBe(0, + "Unix handshake SessionId should be 0 to enable cross-terminal node reuse"); + } + + [UnixOnlyFact] + public void Handshake_OnUnix_KeyIsDeterministic() + { + // Two handshakes with same options produce identical keys on Unix + // because SessionId is always 0 (not terminal-specific). + // Note: this runs in a single process, so it validates determinism + // rather than cross-terminal behavior (which requires integration testing). + var h1 = new Handshake(HandshakeOptions.NodeReuse); + var h2 = new Handshake(HandshakeOptions.NodeReuse); + + h1.GetKey().ShouldBe(h2.GetKey()); + } + } +} + +#endif diff --git a/src/Shared/CommunicationsUtilities.cs b/src/Shared/CommunicationsUtilities.cs index 8c4f6a50167..708e7151a99 100644 --- a/src/Shared/CommunicationsUtilities.cs +++ b/src/Shared/CommunicationsUtilities.cs @@ -287,8 +287,12 @@ protected Handshake(HandshakeOptions nodeType, bool includeSessionId, string too // Get session ID if needed (expensive call) int sessionId = 0; - if (includeSessionId) + if (includeSessionId && NativeMethodsShared.IsWindows) { + // On Windows, SessionId differentiates RDP sessions. + // On Unix, getsid() returns the session leader PID which differs per terminal, + // preventing cross-terminal node reuse. Use 0 since Unix doesn't need + // RDP-style session isolation. using var currentProcess = Process.GetCurrentProcess(); sessionId = currentProcess.SessionId; }