示例#1
0
        /// <summary>
        /// SWN client invoke WitnessrGetInterfaceList method to retrieve information about the interfaces to which witness client connections can be made.
        /// </summary>
        /// <param name="InterfaceList">A pointer to a PWITNESS_INTERFACE_LIST, as specified in section 2.2.1.9.</param>
        /// <returns>Return zero if success, otherwise return nonzero.</returns>
        public int WitnessrGetInterfaceList(out WITNESS_INTERFACE_LIST InterfaceList)
        {
            Int3264[] paramList;
            int       retVal = 0;

            paramList = new Int3264[] {
                IntPtr.Zero, //out param
                IntPtr.Zero  //return value
            };

            using (RpceInt3264Collection outParamList = RpceCall(paramList, (ushort)SWN_OPNUM.WitnessrGetInterfaceList))
            {
                WITNESS_INTERFACE_LIST_RPC rpcList  = TypeMarshal.ToStruct <WITNESS_INTERFACE_LIST_RPC>(Marshal.ReadIntPtr(outParamList[0]));
                WITNESS_INTERFACE_INFO[]   infoList = new WITNESS_INTERFACE_INFO[rpcList.NumberOfInterfaces];
                int sizeInByte = Marshal.SizeOf(typeof(WITNESS_INTERFACE_INFO));
                for (int i = 0; i < rpcList.NumberOfInterfaces; i++)
                {
                    IntPtr pInfo = IntPtrUtility.Add(rpcList.InterfaceInfo, i * sizeInByte);
                    infoList[i] = (WITNESS_INTERFACE_INFO)Marshal.PtrToStructure(pInfo, typeof(WITNESS_INTERFACE_INFO));
                }

                InterfaceList = new WITNESS_INTERFACE_LIST();
                InterfaceList.NumberOfInterfaces = rpcList.NumberOfInterfaces;
                InterfaceList.InterfaceInfo      = infoList;

                retVal = outParamList[paramList.Length - 1].ToInt32();
            }
            return(retVal);
        }
        private void FileServerFailoverTest(string server, FileServerType fsType, bool reconnectWithoutFailover = false)
        {
            int ret = 0;
            uint callId = 0;
            IPAddress currentAccessIpAddr = null;
            WITNESS_INTERFACE_INFO registerInterface = new WITNESS_INTERFACE_INFO();
            WITNESS_INTERFACE_LIST interfaceList = new WITNESS_INTERFACE_LIST();

            currentAccessIpAddr = SWNTestUtility.GetCurrentAccessIP(server);
            BaseTestSite.Log.Add(LogEntryKind.Debug, "Get current file server IP: {0}.", currentAccessIpAddr);

            #region Register SWN witness
            if (witnessType == WitnessType.SwnWitness)
            {
                if (TestConfig.IsWindowsPlatform && fsType == FileServerType.ScaleOutFileServer)
                {
                    // Windows Server: when stopping a non-owner node of ScaleOutFS, no notication will be sent by SMB witness.
                    // So get one IP of the owner node of ScaleOutFS to access.
                    string resourceOwnerNode = sutController.GetClusterResourceOwner(server);
                    IPAddress[] ownerIpList = Dns.GetHostEntry(resourceOwnerNode).AddressList;
                    foreach (var ip in ownerIpList)
                    {
                        BaseTestSite.Log.Add(LogEntryKind.Debug, "Owner IP: {0}", ip);
                    }
                    if (!ownerIpList.Contains(currentAccessIpAddr))
                    {
                        currentAccessIpAddr = null;
                        IPAddress[] accessIpList = Dns.GetHostEntry(server).AddressList;
                        foreach (var ip in accessIpList)
                        {
                            if (ownerIpList.Contains(ip))
                            {
                                currentAccessIpAddr = ip;
                                break;
                            }
                        }
                        BaseTestSite.Assert.IsNotNull(currentAccessIpAddr, "IP should not be null.");
                        BaseTestSite.Log.Add(LogEntryKind.Debug, "Get the owner IP {0} as file server IP.", currentAccessIpAddr);
                    }

                    DoUntilSucceed(() => SWNTestUtility.BindServer(swnClientForInterface, currentAccessIpAddr,
                        TestConfig.DomainName, TestConfig.UserName, TestConfig.UserPassword, TestConfig.DefaultSecurityPackage,
                        TestConfig.DefaultRpceAuthenticationLevel, TestConfig.Timeout, resourceOwnerNode), TestConfig.FailoverTimeout,
                        "Retry BindServer until succeed within timeout span");
                }
                else
                {
                    DoUntilSucceed(() => SWNTestUtility.BindServer(swnClientForInterface, currentAccessIpAddr,
                        TestConfig.DomainName, TestConfig.UserName, TestConfig.UserPassword, TestConfig.DefaultSecurityPackage,
                        TestConfig.DefaultRpceAuthenticationLevel, TestConfig.Timeout, server), TestConfig.FailoverTimeout,
                        "Retry BindServer until succeed within timeout span");
                }

                DoUntilSucceed(() =>
                {
                    ret = swnClientForInterface.WitnessrGetInterfaceList(out interfaceList);
                    BaseTestSite.Assert.AreEqual<SwnErrorCode>(
                        SwnErrorCode.ERROR_SUCCESS,
                        (SwnErrorCode)ret,
                        "WitnessrGetInterfaceList returns with result code = 0x{0:x8}", ret);
                    return SWNTestUtility.VerifyInterfaceList(interfaceList, TestConfig.Platform);
                }, TestConfig.FailoverTimeout, "Retry to call WitnessrGetInterfaceList until succeed within timeout span.");

                SWNTestUtility.GetRegisterInterface(interfaceList, out registerInterface);

                DoUntilSucceed(() => SWNTestUtility.BindServer(swnClientForWitness,
                    (registerInterface.Flags & (uint)SwnNodeFlagsValue.IPv4) != 0 ? new IPAddress(registerInterface.IPV4) : SWNTestUtility.ConvertIPV6(registerInterface.IPV6),
                    TestConfig.DomainName, TestConfig.UserName, TestConfig.UserPassword, TestConfig.DefaultSecurityPackage,
                    TestConfig.DefaultRpceAuthenticationLevel, TestConfig.Timeout, registerInterface.InterfaceGroupName), TestConfig.FailoverTimeout,
                    "Retry BindServer until succeed within timeout span");

                string clientName = Guid.NewGuid().ToString();

                BaseTestSite.Log.Add(LogEntryKind.Debug, "Register witness:");
                BaseTestSite.Log.Add(LogEntryKind.Debug, "\tNetName: {0}", SWNTestUtility.GetPrincipleName(TestConfig.DomainName, server));
                BaseTestSite.Log.Add(LogEntryKind.Debug, "\tIPAddress: {0}", currentAccessIpAddr.ToString());
                BaseTestSite.Log.Add(LogEntryKind.Debug, "\tClient Name: {0}", clientName);

                ret = swnClientForWitness.WitnessrRegister(SwnVersion.SWN_VERSION_1, SWNTestUtility.GetPrincipleName(TestConfig.DomainName, server),
                    currentAccessIpAddr.ToString(), clientName, out pContext);
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(
                    SwnErrorCode.ERROR_SUCCESS,
                    (SwnErrorCode)ret,
                    "WitnessrRegister returns with result code = 0x{0:x8}", ret);
                BaseTestSite.Assert.IsNotNull(
                    pContext,
                    "Expect pContext is not null.");

                callId = swnClientForWitness.WitnessrAsyncNotify(pContext);
                BaseTestSite.Assert.AreNotEqual<uint>(
                    0,
                    callId,
                    "WitnessrAsyncNotify returns callId = {0}", callId);
            }
            #endregion

            #region Create a file and write content
            string uncSharePath = Smb2Utility.GetUncPath(server, TestConfig.ClusteredFileShare);
            string content = Smb2Utility.CreateRandomString(TestConfig.WriteBufferLengthInKb);
            string testDirectory = CreateTestDirectory(uncSharePath);
            string file = Path.Combine(testDirectory, Guid.NewGuid().ToString());
            Guid clientGuid = Guid.NewGuid();
            Guid createGuid = Guid.NewGuid();

            DoUntilSucceed(() => WriteContentBeforeFailover(fsType, server, currentAccessIpAddr, uncSharePath, file, content, clientGuid, createGuid),
                    TestConfig.FailoverTimeout,
                    "Before failover, retry Write content until succeed within timeout span.");
            #endregion

            #region Disable accessed node

            if (TestConfig.IsWindowsPlatform)
            {
                AssignCurrentAccessNode(server, fsType, currentAccessIpAddr);
            }

            if (!reconnectWithoutFailover)
            {
                BaseTestSite.Log.Add(
                    LogEntryKind.TestStep,
                    "Disable owner node for general file server or the node currently provides the access for scale-out file server.");
                FailoverServer(currentAccessIpAddr, server, fsType);
            }

            #endregion

            #region Wait for available server
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Wait for available server.");
            if (witnessType == WitnessType.None)
            {
                if (fsType == FileServerType.GeneralFileServer)
                {
                    currentAccessIpAddr = null;
                    IPAddress[] accessIpList = Dns.GetHostEntry(server).AddressList;
                    DoUntilSucceed(() =>
                    {
                        foreach (IPAddress ipAddress in accessIpList)
                        {
                            Smb2FunctionalClient pingClient = new Smb2FunctionalClient(TestConfig.FailoverTimeout, TestConfig, BaseTestSite);

                            try
                            {
                                pingClient.ConnectToServerOverTCP(ipAddress);
                                pingClient.Disconnect();
                                pingClient = null;

                                currentAccessIpAddr = ipAddress;
                                return true;
                            }
                            catch
                            {
                            }
                        }
                        return false;
                    }, TestConfig.FailoverTimeout, "Retry to ping to server until succeed within timeout span");
                }
                else
                {
                    currentAccessIpAddr = null;

                    IPAddress[] accessIpList = Dns.GetHostEntry(server).AddressList;
                    foreach (IPAddress ipAddress in accessIpList)
                    {
                        if (TestConfig.IsWindowsPlatform)
                        {
                            // When setting failover mode to StopNodeService for Windows, SMB2 servers on two nodes can still be accessed by the client.
                            // So the client needs to get the new node to access it after failover by comparing host name.
                            if (string.Compare(currentAccessNode, Dns.GetHostEntry(ipAddress).HostName, true) == 0)
                            {
                                continue;
                            }
                        }
                        Smb2FunctionalClient pingClient = new Smb2FunctionalClient(TestConfig.FailoverTimeout, TestConfig, BaseTestSite);

                        try
                        {
                            pingClient.ConnectToServerOverTCP(ipAddress);
                            pingClient.Disconnect();
                            pingClient = null;

                            currentAccessIpAddr = ipAddress;
                            break;
                        }
                        catch
                        {
                        }
                    }
                }
            }
            else if (witnessType == WitnessType.SwnWitness)
            {
                // Verifying for notification
                RESP_ASYNC_NOTIFY respNotify;
                do
                {
                    // Wait the notification
                    ret = swnClientForWitness.ExpectWitnessrAsyncNotify(callId, out respNotify);
                    BaseTestSite.Assert.AreEqual<SwnErrorCode>(
                        SwnErrorCode.ERROR_SUCCESS,
                        (SwnErrorCode)ret,
                        "ExpectWitnessrAsyncNotify returns with result code = 0x{0:x8}", ret);
                    SWNTestUtility.PrintNotification(respNotify);

                    RESOURCE_CHANGE[] resourceChangeList;
                    SwnUtility.ParseResourceChange(respNotify, out resourceChangeList);
                    BaseTestSite.Assert.AreEqual<uint>(0x00000001, respNotify.NumberOfMessages, "Expect NumberOfMessages is set to 1.");

                    if (resourceChangeList[0].ChangeType == (uint)SwnResourceChangeType.RESOURCE_STATE_AVAILABLE)
                    {
                        // Verify RESP_ASYNC_NOTIFY, the resource is available
                        SWNTestUtility.VerifyResourceChange(respNotify, SwnResourceChangeType.RESOURCE_STATE_AVAILABLE);
                        break;
                    }

                    // Verify RESP_ASYNC_NOTIFY, the resource is unavailable
                    SWNTestUtility.VerifyResourceChange(respNotify, SwnResourceChangeType.RESOURCE_STATE_UNAVAILABLE);

                    callId = swnClientForWitness.WitnessrAsyncNotify(pContext);
                    BaseTestSite.Assert.AreNotEqual<uint>(0, callId, "WitnessrAsyncNotify returns callId = {0}", callId);
                } while (true);

                ret = swnClientForWitness.WitnessrUnRegister(pContext);
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(
                    SwnErrorCode.ERROR_SUCCESS,
                    (SwnErrorCode)ret,
                    "WitnessrUnRegister returns with result code = 0x{0:x8}", ret);
                pContext = IntPtr.Zero;
                swnClientForWitness.SwnUnbind(TestConfig.Timeout);

                if (fsType == FileServerType.ScaleOutFileServer)
                {
                    // For scale-out file server case, retrieve and use another access IP for connection
                    currentAccessIpAddr =
                        (registerInterface.Flags & (uint)SwnNodeFlagsValue.IPv4) != 0 ? new IPAddress(registerInterface.IPV4) : SWNTestUtility.ConvertIPV6(registerInterface.IPV6);
                }
            }
            #endregion

            #region Read content and close the file
            DoUntilSucceed(() => ReadContentAfterFailover(server, currentAccessIpAddr, uncSharePath, file, content, clientGuid, createGuid),
                    TestConfig.FailoverTimeout,
                    "After failover, retry Read content until succeed within timeout span.");
            #endregion
        }
 public static void PrintInterfaceList(WITNESS_INTERFACE_LIST interfaceList)
 {
     BaseTestSite.Log.Add(LogEntryKind.Debug, "WITNESS_INTERFACE_LIST length: {0}", interfaceList.NumberOfInterfaces);
     for (int i = 0; i < interfaceList.NumberOfInterfaces; i++)
     {
         BaseTestSite.Log.Add(LogEntryKind.Debug, "\tInterface {0}:", i);
         BaseTestSite.Log.Add(LogEntryKind.Debug, "\t\tInterfaceGroupName: {0}", interfaceList.InterfaceInfo[i].InterfaceGroupName);
         BaseTestSite.Log.Add(LogEntryKind.Debug, "\t\tVersion: {0:x8}", interfaceList.InterfaceInfo[i].Version);
         BaseTestSite.Log.Add(LogEntryKind.Debug, "\t\tNodeState: {0}", interfaceList.InterfaceInfo[i].NodeState);
         BaseTestSite.Log.Add(LogEntryKind.Debug, "\t\tIPV4: {0}", (new IPAddress(interfaceList.InterfaceInfo[i].IPV4)).ToString());
         BaseTestSite.Log.Add(LogEntryKind.Debug, "\t\tIPV6: {0}", ConvertIPV6(interfaceList.InterfaceInfo[i].IPV6).ToString());
         BaseTestSite.Log.Add(LogEntryKind.Debug, "\t\tFlags: {0:x8}", interfaceList.InterfaceInfo[i].Flags);
     }
 }
        /// <summary>
        /// Verify the interface list.
        /// </summary>
        /// <param name="interfaceList">The interface list from server.</param>
        /// <param name="platform">SUT platform.</param>
        /// <param name="failCaseIfProtocolVersionIsInvalid">Indicates if failing the case if the verification of protocol version fails</param>
        public static bool VerifyInterfaceList(WITNESS_INTERFACE_LIST interfaceList, Platform platform, bool failCaseIfProtocolVersionIsInvalid = false)
        {
            bool ret = false;

            PrintInterfaceList(interfaceList);
            BaseTestSite.Assert.AreNotEqual<uint>(0, interfaceList.NumberOfInterfaces, "WitnessrGetInterfaceList MUST return at least one available interface.");

            foreach (var info in interfaceList.InterfaceInfo)
            {
                if (info.InterfaceGroupName == "")
                {
                    BaseTestSite.Assert.Fail("The InterfaceGroupName is empty.");
                }

                if (info.NodeState == SwnNodeState.AVAILABLE && (info.Flags & (uint)SwnNodeFlagsValue.INTERFACE_WITNESS) != 0)
                {
                    ret = true;
                }

                #region Check Version
                if (platform == Platform.NonWindows)
                {
                    switch ((SwnVersion)info.Version)
                    {
                        case SwnVersion.SWN_VERSION_1:
                            BaseTestSite.Log.Add(LogEntryKind.Debug,
                                "The Version of SWN service on {0} is 0x{1:x8}",
                                info.InterfaceGroupName,
                                (uint)SwnVersion.SWN_VERSION_1);
                            break;
                        case SwnVersion.SWN_VERSION_2:
                            BaseTestSite.Log.Add(LogEntryKind.Debug,
                                "The Version of SWN service on {0} is 0x{1:x8}",
                                info.InterfaceGroupName,
                                (uint)SwnVersion.SWN_VERSION_2);
                            break;
                        default:
                            BaseTestSite.Assert.Fail(
                                "The Version of SWN service on {0} is unknown 0x{1:x8}",
                                info.InterfaceGroupName,
                                info.Version);
                            break;
                    }
                }
                else
                {
                    if (platform == Platform.WindowsServer2012R2)
                    {
                        BaseTestSite.Assert.AreEqual<SwnVersion>(SwnVersion.SWN_VERSION_UNKNOWN,
                            (SwnVersion)info.Version,
                            "Expect the Version of SWN service on {0} is 0x{1:x8}",
                            info.InterfaceGroupName,
                            (uint)SwnVersion.SWN_VERSION_UNKNOWN);
                    }
                    else if (platform == Platform.WindowsServer2012)
                    {
                        BaseTestSite.Assert.AreEqual<SwnVersion>(SwnVersion.SWN_VERSION_1,
                            (SwnVersion)info.Version,
                            "Expect the Version of SWN service on {0} is 0x{1:x8}",
                            info.InterfaceGroupName,
                            (uint)SwnVersion.SWN_VERSION_1);
                    }
                    else if (platform == Platform.WindowsServer2016)
                    {
                        if (info.Version == (uint)SwnVersion.SWN_VERSION_UNKNOWN)
                        {

                        }
                        else
                        {
                            BaseTestSite.Assert.AreEqual<SwnVersion>(SwnVersion.SWN_VERSION_2,
                                (SwnVersion)info.Version,
                                "Expect the Version of SWN service on {0} is 0x{1:x8}",
                                info.InterfaceGroupName,
                                (uint)SwnVersion.SWN_VERSION_2);
                        }
                    }
                    else
                    {
                        BaseTestSite.Assert.Fail(
                            "The Version of SWN service on {0} is unknown 0x{1:x8}",
                            info.InterfaceGroupName,
                            info.Version);
                    }
                }
                #endregion

                if ((info.Flags & (uint)SwnNodeFlagsValue.IPv4) != 0 && info.IPV4 == 0)
                {
                    BaseTestSite.Assert.Fail("The IPV4 {0} of {1} is invalid.",
                        new IPAddress(info.IPV4).ToString(), info.InterfaceGroupName);
                }
                else if ((info.Flags & (uint)SwnNodeFlagsValue.IPv6) != 0 && info.IPV6.All(ip => ip == 0))
                {
                    BaseTestSite.Assert.Fail("The IPV6 {0} of {1} is invalid.",
                        ConvertIPV6(info.IPV6).ToString(), info.InterfaceGroupName);
                }
            }

            return ret;
        }
        /// <summary>
        /// Get the list of InterfaceGroupName.
        /// </summary>
        /// <param name="interfaceList">The interface list from server.</param>
        /// <returns>InterfaceGroupName array. 
        /// Index 0: InterfaceGroupName of the registered node.
        /// Index 1: InterfaceGroupName of the witnessed node.</returns>
        public static string[] GetInterfaceGroupName(WITNESS_INTERFACE_LIST interfaceList)
        {
            // TODO:
            string[] interfaceGroupName = new string[2];

            foreach (var info in interfaceList.InterfaceInfo)
            {
                if ((info.Flags & (uint)SwnNodeFlagsValue.INTERFACE_WITNESS) != 0)
                {
                    // InterfaceGroupName of the registered node.
                    interfaceGroupName[0] = info.InterfaceGroupName;
                }
                if ((info.Flags & (uint)SwnNodeFlagsValue.INTERFACE_WITNESS) == 0)
                {
                    // InterfaceGroupName of the witnessed node.
                    interfaceGroupName[1] = info.InterfaceGroupName;
                }
            }

            return interfaceGroupName;
        }
        /// <summary>
        /// Get the witness server to be used to register.
        /// </summary>
        /// <param name="interfaceList">The interface list from server.</param>
        /// <param name="registerInterface">Interface to register.</param>
        public static void GetRegisterInterface(WITNESS_INTERFACE_LIST interfaceList, out WITNESS_INTERFACE_INFO registerInterface)
        {
            registerInterface = new WITNESS_INTERFACE_INFO();

            foreach (var info in interfaceList.InterfaceInfo)
            {
                if (info.NodeState == SwnNodeState.AVAILABLE && (info.Flags & (uint)SwnNodeFlagsValue.INTERFACE_WITNESS) != 0)
                {
                    registerInterface = info;

                    BaseTestSite.Log.Add(LogEntryKind.Debug, "Register to interface:");
                    BaseTestSite.Log.Add(LogEntryKind.Debug, "\tInterface group name: {0}", registerInterface.InterfaceGroupName);
                    BaseTestSite.Log.Add(LogEntryKind.Debug, "\tInterface IPV4 address: {0}", new IPAddress(registerInterface.IPV4).ToString());
                    BaseTestSite.Log.Add(LogEntryKind.Debug, "\tInterface IPV6 address: {0}", SWNTestUtility.ConvertIPV6(registerInterface.IPV6).ToString());
                    return;
                }
            }

            BaseTestSite.Assert.Fail("Cannot get register interface.");
        }
        private void SWNRegister(SwnRegisterType registerType, SwnVersion expectedVersion)
        {
            WITNESS_INTERFACE_INFO registerInterface;
            IntPtr pDuplicateContext = IntPtr.Zero;
            swnClientForInterface = new SwnClient();
            swnClientForWitness = new SwnClient();
            string server = TestConfig.ClusteredFileServerName;

            IPAddress currentAccessIpAddr = SWNTestUtility.GetCurrentAccessIP(server);

            #region Get SWN witness interface list
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Get SWN witness interface list.");

            DoUntilSucceed(() => SWNTestUtility.BindServer(swnClientForInterface, currentAccessIpAddr,
                TestConfig.DomainName, TestConfig.UserName, TestConfig.UserPassword, TestConfig.DefaultSecurityPackage,
                TestConfig.DefaultRpceAuthenticationLevel, TestConfig.Timeout, server), TestConfig.FailoverTimeout,
                "Retry BindServer until succeed within timeout span");

            int ret;
            WITNESS_INTERFACE_LIST interfaceList = new WITNESS_INTERFACE_LIST();

            DoUntilSucceed(() =>
            {
                ret = swnClientForInterface.WitnessrGetInterfaceList(out interfaceList);
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrGetInterfaceList returns with result code = 0x{0:x8}", ret);
                return SWNTestUtility.VerifyInterfaceList(interfaceList, TestConfig.Platform);
            }, TestConfig.FailoverTimeout, "Retry to call WitnessrGetInterfaceList until succeed within timeout span");

            swnClientForInterface.SwnUnbind(TestConfig.Timeout);
            swnClientForInterface = null;

            SWNTestUtility.GetRegisterInterface(interfaceList, out registerInterface);

            SWNTestUtility.CheckVersion(expectedVersion, (SwnVersion)registerInterface.Version);
            #endregion

            #region Register SWN witness
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Register SWN witness with {0}.", registerType.ToString());

            DoUntilSucceed(() => SWNTestUtility.BindServer(swnClientForWitness,
                (registerInterface.Flags & (uint)SwnNodeFlagsValue.IPv4) != 0 ? new IPAddress(registerInterface.IPV4) : SWNTestUtility.ConvertIPV6(registerInterface.IPV6),
                TestConfig.DomainName, TestConfig.UserName, TestConfig.UserPassword, TestConfig.DefaultSecurityPackage,
                TestConfig.DefaultRpceAuthenticationLevel, TestConfig.Timeout), TestConfig.FailoverTimeout,
                "Retry BindServer until succeed within timeout span");

            SwnVersion registerVersion;
            if (SwnVersion.SWN_VERSION_2 == expectedVersion)
                registerVersion = (registerType == SwnRegisterType.InvalidVersion ? SwnVersion.SWN_VERSION_1 : SwnVersion.SWN_VERSION_2);
            else
                registerVersion = (registerType == SwnRegisterType.InvalidVersion ? SwnVersion.SWN_VERSION_2 : SwnVersion.SWN_VERSION_1);
            string registerNetName =
                (registerType == SwnRegisterType.InvalidNetName ? "XXXXInvalid.contoso.comXXXX" : SWNTestUtility.GetPrincipleName(TestConfig.DomainName, server));
            string accessIpAddr =
                (registerType == SwnRegisterType.InvalidIpAddress ? "255.255.255.255" : currentAccessIpAddr.ToString());
            string registerClientName = Guid.NewGuid().ToString();
            string shareName =
                (registerType == SwnRegisterType.InvalidShareName ? "XXXXInvalidShareNameXXXX" : TestConfig.ClusteredFileShare);
            uint keepAliveTimout =
                (registerType == SwnRegisterType.KeepAliveTimeout ? (uint)10 : (uint)120);

            BaseTestSite.Log.Add(LogEntryKind.Debug, "Register witness:");
            BaseTestSite.Log.Add(LogEntryKind.Debug, "\tVersion: {0:x8}", (uint)registerVersion);
            BaseTestSite.Log.Add(LogEntryKind.Debug, "\tNetName: {0}", registerNetName);
            BaseTestSite.Log.Add(LogEntryKind.Debug, "\tShareName: {0}", shareName);
            BaseTestSite.Log.Add(LogEntryKind.Debug, "\tIpAddress: {0}", accessIpAddr);
            BaseTestSite.Log.Add(LogEntryKind.Debug, "\tClientName: {0}", registerClientName);
            if (SwnVersion.SWN_VERSION_2 == expectedVersion)
            {
                ret = swnClientForWitness.WitnessrRegisterEx(registerVersion,
                    registerNetName,
                    shareName,
                    accessIpAddr,
                    registerClientName,
                    WitnessrRegisterExFlagsValue.WITNESS_REGISTER_NONE,
                    keepAliveTimout,
                    out pContext);
            }
            else
            {
                ret = swnClientForWitness.WitnessrRegister(registerVersion,
                    registerNetName,
                    accessIpAddr,
                    registerClientName,
                    out pContext);
            }

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Verify server response for WitnessrRegister request.");

            // TDI to be filed, original fix for TDI 66777 and 69401 is not accurate, need clarify in new TDI
            // Windows server won't fail the request if the target resource being monitored is ScaleOut FS share when request containst invalid IP address or invalid share name
            // TODO: Test case should have ability to choose different server, otherwise we do not need such condition
            bool isScaleOutFsShare = ShareContainsSofs(server, Smb2Utility.GetUncPath(server, TestConfig.ClusteredFileShare));

            if (registerType == SwnRegisterType.InvalidNetName)
            {
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_INVALID_PARAMETER, (SwnErrorCode)ret, "WitnessrRegister returns with result code = 0x{0:x8}", ret);
            }
            else if (registerType == SwnRegisterType.InvalidVersion)
            {
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_REVISION_MISMATCH, (SwnErrorCode)ret, "WitnessrRegister returns with result code = 0x{0:x8}", ret);
            }
            else if (registerType == SwnRegisterType.InvalidIpAddress)
            {
                if (!isScaleOutFsShare)
                {
                    BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrRegister returns with result code = 0x{0:x8}", ret);
                }
                else
                {
                    BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_INVALID_STATE, (SwnErrorCode)ret, "WitnessrRegister returns with result code = 0x{0:x8}", ret);
                }
            }
            else if (registerType == SwnRegisterType.InvalidShareName)
            {
                if (!isScaleOutFsShare)
                {
                    BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrRegister returns with result code = 0x{0:x8}", ret);
                }
                else
                {
                    BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_INVALID_STATE, (SwnErrorCode)ret, "WitnessrRegister returns with result code = 0x{0:x8}", ret);
                }
            }
            else
            {
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrRegister returns with result code = 0x{0:x8}", ret);
            }

            if (registerType == SwnRegisterType.InvalidUnRegister)
            {
                ret = swnClientForWitness.WitnessrUnRegister(pContext);
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrUnRegister returns with result code = 0x{0:x8}", ret);

                ret = swnClientForWitness.WitnessrUnRegister(pContext);
                if (TestConfig.Platform == Platform.WindowsServer2012)
                {
                    BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_NOT_FOUND, (SwnErrorCode)ret, "WitnessrUnRegister returns with result code = 0x{0:x8}", ret);
                }
                else
                {
                    BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_INVALID_PARAMETER, (SwnErrorCode)ret, "WitnessrUnRegister returns with result code = 0x{0:x8}", ret);
                }
                pContext = IntPtr.Zero;
                swnClientForWitness.SwnUnbind(TestConfig.Timeout);
            }

            if (registerType == SwnRegisterType.InvalidRequest)
            {
                ret = swnClientForWitness.WitnessrUnRegister(pContext);
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrUnRegister returns with result code = 0x{0:x8}", ret);

                uint callId;
                callId = swnClientForWitness.WitnessrAsyncNotify(pContext);
                BaseTestSite.Assert.AreNotEqual<uint>(0, callId, "WitnessrAsyncNotify returns callId = {0}", callId);

                RESP_ASYNC_NOTIFY respNotify;
                ret = swnClientForWitness.ExpectWitnessrAsyncNotify(callId, out respNotify);
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_NOT_FOUND, (SwnErrorCode)ret, "ExpectWitnessrAsyncNotify returns with result code = 0x{0:x8}", ret);

                pContext = IntPtr.Zero;
                swnClientForWitness.SwnUnbind(TestConfig.Timeout);
            }

            if (registerType == SwnRegisterType.KeepAliveTimeout)
            {
                uint callId;
                callId = swnClientForWitness.WitnessrAsyncNotify(pContext);
                BaseTestSite.Assert.AreNotEqual<uint>(0, callId, "WitnessrAsyncNotify returns callId = {0}", callId);

                RESP_ASYNC_NOTIFY respNotify;
                ret = swnClientForWitness.ExpectWitnessrAsyncNotify(callId, out respNotify);
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_TIMEOUT, (SwnErrorCode)ret, "ExpectWitnessrAsyncNotify returns with result code = 0x{0:x8}", ret);

                pContext = IntPtr.Zero;
                swnClientForWitness.SwnUnbind(TestConfig.Timeout);
            }
            #endregion

            #region Cleanup
            pContext = IntPtr.Zero;
            swnClientForWitness.SwnUnbind(TestConfig.Timeout);
            swnClientForWitness = null;
            #endregion
        }
        private void SWNAsyncNotification_IPChange(SwnMessageType messageType)
        {
            int ret = 0;
            uint callId = 0;
            WITNESS_INTERFACE_INFO registerInterface;
            string server = TestConfig.ClusteredScaleOutFileServerName;

            #region Get the file server IP and access it through SMB2
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Get the file server Ip and access it through SMB2.");
            IPAddress currentAccessIp = SWNTestUtility.GetCurrentAccessIP(server);
            BaseTestSite.Assert.AreNotEqual(null, currentAccessIp, "IP address of the file server should NOT be empty");
            BaseTestSite.Log.Add(LogEntryKind.Debug, "IP address of the file server is {0}.", currentAccessIp.ToString());

            #endregion

            #region Get interface list to register.
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Get interface list to register.");
            DoUntilSucceed(() => SWNTestUtility.BindServer(swnClientForInterface, currentAccessIp,
                TestConfig.DomainName, TestConfig.UserName, TestConfig.UserPassword, TestConfig.DefaultSecurityPackage,
                TestConfig.DefaultRpceAuthenticationLevel, TestConfig.Timeout, server), TestConfig.FailoverTimeout,
                "Retry BindServer until succeed within timeout span");

            WITNESS_INTERFACE_LIST interfaceList = new WITNESS_INTERFACE_LIST();
            DoUntilSucceed(() =>
            {
                ret = swnClientForInterface.WitnessrGetInterfaceList(out interfaceList);
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrGetInterfaceList returns with result code = 0x{0:x8}", ret);
                return SWNTestUtility.VerifyInterfaceList(interfaceList, TestConfig.Platform);
            }, TestConfig.FailoverTimeout, "Retry to call WitnessrGetInterfaceList until succeed within timeout span");

            swnClientForInterface.SwnUnbind(TestConfig.Timeout);

            SWNTestUtility.GetRegisterInterface(interfaceList, out registerInterface);

            SWNTestUtility.CheckVersion(SwnVersion.SWN_VERSION_2, (SwnVersion)registerInterface.Version);
            #endregion

            #region Register SWN witness
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Register SWN witness.");
            DoUntilSucceed(() => SWNTestUtility.BindServer(swnClientForWitness,
                (registerInterface.Flags & (uint)SwnNodeFlagsValue.IPv4) != 0 ? new IPAddress(registerInterface.IPV4) : SWNTestUtility.ConvertIPV6(registerInterface.IPV6),
                TestConfig.DomainName, TestConfig.UserName, TestConfig.UserPassword, TestConfig.DefaultSecurityPackage,
                TestConfig.DefaultRpceAuthenticationLevel, TestConfig.Timeout, server), TestConfig.FailoverTimeout,
                "Retry BindServer until succeed within timeout span");

            string clientName = Guid.NewGuid().ToString();
            string netName = SWNTestUtility.GetPrincipleName(TestConfig.DomainName, server);
            string shareName = TestConfig.ClusteredFileShare;
            WitnessrRegisterExFlagsValue flag = WitnessrRegisterExFlagsValue.WITNESS_REGISTER_NONE;
            if (messageType == SwnMessageType.IP_CHANGE_NOTIFICATION)
                flag = WitnessrRegisterExFlagsValue.WITNESS_REGISTER_IP_NOTIFICATION;

            BaseTestSite.Log.Add(LogEntryKind.Debug, "Register witness:");
            BaseTestSite.Log.Add(LogEntryKind.Debug, "\tNetName: {0}", netName);
            BaseTestSite.Log.Add(LogEntryKind.Debug, "\tIPAddress: {0}", currentAccessIp.ToString());
            BaseTestSite.Log.Add(LogEntryKind.Debug, "\tClient Name: {0}", clientName);

            ret = swnClientForWitness.WitnessrRegisterEx(SwnVersion.SWN_VERSION_2,
                netName,
                shareName,
                currentAccessIp.ToString(),
                clientName,
                flag,
                120,
                out pContext);
            BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrRegisterEx returns with result code = 0x{0:x8}", ret);

            BaseTestSite.Assert.IsNotNull(pContext, "Expect pContext is not null.");

            // Reboot witness node (Restart witness service), cause SHARE_MOVE_NOTIFICATION
            callId = swnClientForWitness.WitnessrAsyncNotify(pContext);
            BaseTestSite.Assert.AreNotEqual<uint>(0, callId, "WitnessrAsyncNotify returns callId = {0}", callId);
            RESP_ASYNC_NOTIFY respNotify;

            ret = swnClientForWitness.ExpectWitnessrAsyncNotify(callId, out respNotify);
            BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrAsyncNotify returns with result code = 0x{0:x8}", ret);
            SWNTestUtility.PrintNotification(respNotify);
            SWNTestUtility.VerifyClientMoveShareMoveAndIpChange(respNotify, SwnMessageType.SHARE_MOVE_NOTIFICATION, (uint)SwnIPAddrInfoFlags.IPADDR_V4, TestConfig.Platform);
            #endregion

            #region Trigger Notification
            if (messageType == SwnMessageType.IP_CHANGE_NOTIFICATION)
            {
                #region Refresh network adapter on node to trigger IP_CHANGE_NOTIFICATION
                callId = swnClientForWitness.WitnessrAsyncNotify(pContext);
                BaseTestSite.Assert.AreNotEqual<uint>(0, callId, "WitnessrAsyncNotify returns callId = {0}", callId);
                // Refresh an adapter on the node the client is connected, to trigger IP_CHANGE_NOTIFICATION
                BaseTestSite.Log.Add(LogEntryKind.Debug, "Refresh an adapter to trigger IP_CHANGE_NOTIFICATION");
                IPAddress[] addressList = Dns.GetHostEntry(currentAccessIp).AddressList;
                IPAddress refreshIpAddress = null;
                foreach (IPAddress ipAddress in addressList)
                {
                    if (ipAddress.ToString() != currentAccessIp.ToString())
                    {
                        refreshIpAddress = ipAddress;
                        break;
                    }
                }

                BaseTestSite.Log.Add(LogEntryKind.TestStep, "Refresh network adapter on node {0} to trigger IP_CHANGE_NOTIFICATION.", refreshIpAddress.ToString());
                sutController.RefreshNetAdapter(refreshIpAddress.ToString(), Dns.GetHostEntry(currentAccessIp).HostName);
                #endregion

                #region Wait for IP_CHANGE_NOTIFICATION
                BaseTestSite.Log.Add(LogEntryKind.TestStep, "Wait for IP_CHANGE_NOTIFICATION.");

                ret = swnClientForWitness.ExpectWitnessrAsyncNotify(callId, out respNotify);
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrAsyncNotify returns with result code = 0x{0:x8}", ret);
                SWNTestUtility.PrintNotification(respNotify);
                SWNTestUtility.VerifyClientMoveShareMoveAndIpChange(respNotify, SwnMessageType.IP_CHANGE_NOTIFICATION, (uint)(SwnIPAddrInfoFlags.IPADDR_V4 | SwnIPAddrInfoFlags.IPADDR_OFFLINE), TestConfig.Platform);
                // Wait the IP_CHANGE_NOTIFICATION
                callId = swnClientForWitness.WitnessrAsyncNotify(pContext);
                BaseTestSite.Assert.AreNotEqual<uint>(0, callId, "WitnessrAsyncNotify returns callId = {0}", callId);
                ret = swnClientForWitness.ExpectWitnessrAsyncNotify(callId, out respNotify);
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrAsyncNotify returns with result code = 0x{0:x8}", ret);
                SWNTestUtility.PrintNotification(respNotify);
                // Verify RESP_ASYNC_NOTIFY
                SWNTestUtility.VerifyClientMoveShareMoveAndIpChange(respNotify, SwnMessageType.IP_CHANGE_NOTIFICATION, (uint)(SwnIPAddrInfoFlags.IPADDR_V4 | SwnIPAddrInfoFlags.IPADDR_ONLINE), TestConfig.Platform);
                #endregion
            }
            #endregion

            #region Unregister SWN Witness
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Unregister SWN Witness.");

            ret = swnClientForWitness.WitnessrUnRegister(pContext);
            BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrUnRegister returns with result code = 0x{0:x8}", ret);
            pContext = IntPtr.Zero;
            swnClientForWitness.SwnUnbind(TestConfig.Timeout);
            #endregion
        }
        /// <summary>
        /// Test CLIENT_MOVE_NOTIFICATION.
        /// </summary>
        /// <param name="expectedVersion">SwnVersion.SWN_VERSION_2 indicates that register with WitnessrRegisterEx, SwnVersion.SWN_VERSION_1 indicates that register with WitnessrRegister.</param>
        private void SWNAsyncNotification_ClientMove(SwnVersion expectedVersion)
        {
            int ret = 0;
            uint callId = 0;
            WITNESS_INTERFACE_INFO registerInterface;
            string server = TestConfig.ClusteredScaleOutFileServerName;

            #region Get the file server to access it through SMB2

            IPAddress currentAccessIp = SWNTestUtility.GetCurrentAccessIP(server);
            BaseTestSite.Assert.AreNotEqual(null, currentAccessIp, "IP address of the file server should NOT be empty");
            BaseTestSite.Log.Add(LogEntryKind.Debug, "Got the IP {0} to access the file server", currentAccessIp.ToString());

            #endregion

            #region Get register interface

            DoUntilSucceed(() => SWNTestUtility.BindServer(swnClientForInterface, currentAccessIp,
                TestConfig.DomainName, TestConfig.UserName, TestConfig.UserPassword, TestConfig.DefaultSecurityPackage,
                TestConfig.DefaultRpceAuthenticationLevel, TestConfig.Timeout, server), TestConfig.FailoverTimeout,
                "Retry BindServer until succeed within timeout span");

            WITNESS_INTERFACE_LIST interfaceList = new WITNESS_INTERFACE_LIST();

            DoUntilSucceed(() =>
            {
                ret = swnClientForInterface.WitnessrGetInterfaceList(out interfaceList);
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrGetInterfaceList returns with result code = 0x{0:x8}", ret);
                return SWNTestUtility.VerifyInterfaceList(interfaceList, TestConfig.Platform);
            }, TestConfig.FailoverTimeout, "Retry to call WitnessrGetInterfaceList until succeed within timeout span");

            swnClientForInterface.SwnUnbind(TestConfig.Timeout);

            SWNTestUtility.GetRegisterInterface(interfaceList, out registerInterface);

            SWNTestUtility.CheckVersion(expectedVersion, (SwnVersion)registerInterface.Version);
            #endregion

            #region Register SWN witness

            DoUntilSucceed(() => SWNTestUtility.BindServer(swnClientForWitness,
                (registerInterface.Flags & (uint)SwnNodeFlagsValue.IPv4) != 0 ? new IPAddress(registerInterface.IPV4) : SWNTestUtility.ConvertIPV6(registerInterface.IPV6),
                TestConfig.DomainName, TestConfig.UserName, TestConfig.UserPassword, TestConfig.DefaultSecurityPackage,
                TestConfig.DefaultRpceAuthenticationLevel, TestConfig.Timeout, server), TestConfig.FailoverTimeout,
                "Retry BindServer until succeed within timeout span");

            string clientName = Guid.NewGuid().ToString();
            string netName = SWNTestUtility.GetPrincipleName(TestConfig.DomainName, server);

            BaseTestSite.Log.Add(LogEntryKind.Debug, "Register witness:");
            BaseTestSite.Log.Add(LogEntryKind.Debug, "\tNetName: {0}", netName);
            BaseTestSite.Log.Add(LogEntryKind.Debug, "\tIPAddress: {0}", currentAccessIp.ToString());
            BaseTestSite.Log.Add(LogEntryKind.Debug, "\tClient Name: {0}", clientName);

            if (SwnVersion.SWN_VERSION_2 == expectedVersion)
            {
                ret = swnClientForWitness.WitnessrRegisterEx(SwnVersion.SWN_VERSION_2,
                    netName,
                    null,
                    currentAccessIp.ToString(),
                    clientName,
                    WitnessrRegisterExFlagsValue.WITNESS_REGISTER_IP_NOTIFICATION,
                    120,
                    out pContext);
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrRegisterEx returns with result code = 0x{0:x8}", ret);
            }
            else
            {
                ret = swnClientForWitness.WitnessrRegister(SwnVersion.SWN_VERSION_1,
                netName,
                currentAccessIp.ToString(),
                clientName,
                out pContext);
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrRegister returns with result code = 0x{0:x8}", ret);
            }
            BaseTestSite.Assert.IsNotNull(pContext, "Expect pContext is not null.");

            callId = swnClientForWitness.WitnessrAsyncNotify(pContext);
            BaseTestSite.Assert.AreNotEqual<uint>(0, callId, "WitnessrAsyncNotify returns callId = {0}", callId);

            #endregion

            #region Create a file and write content

            string uncSharePath = Smb2Utility.GetUncPath(server, TestConfig.ClusteredFileShare);
            string content = Smb2Utility.CreateRandomString(TestConfig.WriteBufferLengthInKb);
            string testDirectory = CreateTestDirectory(uncSharePath);
            string file = Path.Combine(testDirectory, Guid.NewGuid().ToString());
            Guid clientGuid = Guid.NewGuid();
            Guid createGuid = Guid.NewGuid();
            FileServerType fsType = FileServerType.ScaleOutFileServer;

            DoUntilSucceed(() => WriteContentBeforeFailover(fsType, server, currentAccessIp, uncSharePath, file, content, clientGuid, createGuid),
                    TestConfig.FailoverTimeout,
                    "Before failover, retry Write content until succeed within timeout span.");

            #endregion

            #region Move resource node

            // Move resource node to trigger CLIENT_MOVE_NOTIFICATION
            BaseTestSite.Log.Add(LogEntryKind.Debug, "Move resource to interface {0} to trigger CLIENT_MOVE_NOTIFICATION", registerInterface.InterfaceGroupName);
            sutController.MoveSmbWitnessClient(clientName,
                SWNTestUtility.GetPrincipleName(TestConfig.DomainName, registerInterface.InterfaceGroupName));

            #endregion

            #region Wait CLIENT_MOVE_NOTIFICATION

            RESP_ASYNC_NOTIFY respNotify;
            // Wait the CLIENT_MOVE_NOTIFICATION
            ret = swnClientForWitness.ExpectWitnessrAsyncNotify(callId, out respNotify);
            BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrAsyncNotify returns with result code = 0x{0:x8}", ret);
            SWNTestUtility.PrintNotification(respNotify);

            // Verify RESP_ASYNC_NOTIFY
            SWNTestUtility.VerifyClientMoveShareMoveAndIpChange(respNotify, SwnMessageType.CLIENT_MOVE_NOTIFICATION, (uint)SwnIPAddrInfoFlags.IPADDR_V4, TestConfig.Platform);
            #endregion

            #region Get the new IpAddr
            IPADDR_INFO_LIST ipAddrInfoList;
            SwnUtility.ParseIPAddrInfoList(respNotify, out ipAddrInfoList);
            currentAccessIp = (ipAddrInfoList.IPAddrList[0].Flags & (uint)SwnNodeFlagsValue.IPv4) != 0 ? new IPAddress(ipAddrInfoList.IPAddrList[0].IPV4) : SWNTestUtility.ConvertIPV6(ipAddrInfoList.IPAddrList[0].IPV6);
            #endregion

            #region Unregister SWN Witness

            ret = swnClientForWitness.WitnessrUnRegister(pContext);
            BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrUnRegister returns with result code = 0x{0:x8}", ret);
            pContext = IntPtr.Zero;
            swnClientForWitness.SwnUnbind(TestConfig.Timeout);

            #endregion

            #region Make sure Cluster Share is available
            DoUntilSucceed(() => sutProtocolController.CheckIfShareIsAvailable(uncSharePath),
                testConfig.Timeout,
                "Make sure cluster share is available.");
            #endregion

            #region Read content and close the file
            DoUntilSucceed(() => ReadContentAfterFailover(server, currentAccessIp, uncSharePath, file, content, clientGuid, createGuid),
                    TestConfig.FailoverTimeout,
                    "Retry Read content until succeed within timeout span.");
            #endregion
        }
        private void TestAsymmetricShare(DialectRevision requestMaxDialect, string serverName, bool isAsymmetricShare)
        {
            int ret = 0;
            uint callId = 0;
            Guid clientGuid = Guid.NewGuid();
            WITNESS_INTERFACE_INFO registerInterface;
            string shareName = isAsymmetricShare ? TestConfig.AsymmetricShare : TestConfig.BasicFileShare;

            #region Get the file server to access it through SMB2
            IPAddress currentAccessIp = SWNTestUtility.GetCurrentAccessIP(serverName);
            BaseTestSite.Assert.IsNotNull(currentAccessIp, "IP address of the file server should NOT be empty");
            BaseTestSite.Log.Add(LogEntryKind.Debug, "Got the IP {0} to access the file server", currentAccessIp.ToString());
            #endregion

            #region Connect to the asymmetric share
            uncSharePath = Smb2Utility.GetUncPath(serverName, shareName);
            string content = Smb2Utility.CreateRandomString(TestConfig.WriteBufferLengthInKb);
            testDirectory = CreateTestDirectory(uncSharePath);
            string file = Path.Combine(testDirectory, Guid.NewGuid().ToString());

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start the client by sending the following requests: NEGOTIATE; SESSION_SETUP");
            smb2Client = new Smb2FunctionalClient(TestConfig.FailoverTimeout, TestConfig, BaseTestSite);
            smb2Client.ConnectToServerOverTCP(currentAccessIp);
            smb2Client.Negotiate(
                Smb2Utility.GetDialects(requestMaxDialect),
                TestConfig.IsSMB1NegotiateEnabled,
                capabilityValue: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES,
                clientGuid: clientGuid,
                checker: (Packet_Header header, NEGOTIATE_Response response) =>
                {
                    BaseTestSite.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, header.Status, "Negotiate should succeed.");
                    BaseTestSite.Assert.AreEqual(
                        requestMaxDialect,
                        response.DialectRevision,
                        "The server is expected to use dialect {0}. Actual dialect is {1}",
                        requestMaxDialect,
                        response.DialectRevision);
                });
            smb2Client.SessionSetup(
                TestConfig.DefaultSecurityPackage,
                serverName,
                TestConfig.AccountCredential,
                TestConfig.UseServerGssToken);

            uint treeId = 0;
            Share_Capabilities_Values shareCapabilities = Share_Capabilities_Values.NONE;
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends TREE_CONNECT request to the {0} on the {1}", shareName, serverName);
            DoUntilSucceed(
                () => smb2Client.TreeConnect(uncSharePath, out treeId, (header, response) => { shareCapabilities = response.Capabilities; }),
                TestConfig.FailoverTimeout,
                "Retry TreeConnect until succeed within timeout span");

            if (requestMaxDialect == DialectRevision.Smb302 && isAsymmetricShare)
            {
                BaseTestSite.Assert.IsTrue(shareCapabilities.HasFlag(Share_Capabilities_Values.SHARE_CAP_ASYMMETRIC),
                    "The capabilities of the share should contain SHARE_CAP_ASYMMETRIC. The actual capabilities is {0}.", shareCapabilities);
            }
            else
            {
                BaseTestSite.Assert.IsFalse(shareCapabilities.HasFlag(Share_Capabilities_Values.SHARE_CAP_ASYMMETRIC),
                    "The capabilities of the share should not contain SHARE_CAP_ASYMMETRIC. The actual capabilities is {0}.", shareCapabilities);

                #region Disconnect current SMB2 connection
                smb2Client.TreeDisconnect(treeId);
                smb2Client.LogOff();
                smb2Client.Disconnect();
                #endregion
                return;
            }

            FILEID fileId;
            Smb2CreateContextResponse[] serverCreateContexts;
            Guid createGuid = Guid.NewGuid();
            Guid leaseKey = Guid.NewGuid();
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client writes to the file.");
            smb2Client.Create(
                treeId,
                file,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE | CreateOptions_Values.FILE_DELETE_ON_CLOSE,
                out fileId,
                out serverCreateContexts,
                RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE);
            smb2Client.Write(treeId, fileId, content);

            string readContent;
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client reads from the file.");
            smb2Client.Read(treeId, fileId, 0, (uint)content.Length, out readContent);
            BaseTestSite.Assert.IsTrue(
                content.Equals(readContent),
                "Content read should be identical to that written.");
            #endregion

            #region Get register interface
            DoUntilSucceed(() => SWNTestUtility.BindServer(swnClientForInterface, currentAccessIp,
                TestConfig.DomainName, TestConfig.UserName, TestConfig.UserPassword, TestConfig.DefaultSecurityPackage,
                TestConfig.DefaultRpceAuthenticationLevel, TestConfig.Timeout, serverName), TestConfig.FailoverTimeout,
                "Retry BindServer until succeed within timeout span");

            WITNESS_INTERFACE_LIST interfaceList = new WITNESS_INTERFACE_LIST();
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client calls WitnessrGetInterfaceList.");
            DoUntilSucceed(() =>
            {
                ret = swnClientForInterface.WitnessrGetInterfaceList(out interfaceList);
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrGetInterfaceList returns with result code = 0x{0:x8}", ret);
                return SWNTestUtility.VerifyInterfaceList(interfaceList, TestConfig.Platform);
            }, TestConfig.FailoverTimeout, "Retry to call WitnessrGetInterfaceList until succeed within timeout span");

            swnClientForInterface.SwnUnbind(TestConfig.Timeout);

            SWNTestUtility.GetRegisterInterface(interfaceList, out registerInterface);

            #endregion

            #region Get SHARE_MOVE_NOTIFICATION
            DoUntilSucceed(() => SWNTestUtility.BindServer(swnClientForWitness,
                (registerInterface.Flags & (uint)SwnNodeFlagsValue.IPv4) != 0 ? new IPAddress(registerInterface.IPV4) : SWNTestUtility.ConvertIPV6(registerInterface.IPV6),
                TestConfig.DomainName, TestConfig.UserName, TestConfig.UserPassword, TestConfig.DefaultSecurityPackage,
                TestConfig.DefaultRpceAuthenticationLevel, TestConfig.Timeout, serverName), TestConfig.FailoverTimeout,
                "Retry BindServer until succeed within timeout span");

            string clientName = TestConfig.WitnessClientName;

            BaseTestSite.Log.Add(LogEntryKind.Debug, "Register witness:");
            BaseTestSite.Log.Add(LogEntryKind.Debug, "\tNetName: {0}", serverName);
            BaseTestSite.Log.Add(LogEntryKind.Debug, "\tIPAddress: {0}", currentAccessIp.ToString());
            BaseTestSite.Log.Add(LogEntryKind.Debug, "\tClient Name: {0}", clientName);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client calls WitnessrRegisterEx.");
            ret = swnClientForWitness.WitnessrRegisterEx(SwnVersion.SWN_VERSION_2,
                serverName,
                shareName,
                currentAccessIp.ToString(),
                clientName,
                WitnessrRegisterExFlagsValue.WITNESS_REGISTER_IP_NOTIFICATION,
                120,
                out pContext);
            BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrRegisterEx returns with result code = 0x{0:x8}", ret);

            BaseTestSite.Assert.IsNotNull(pContext, "Expect pContext is not null.");

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client calls WitnessrAsyncNotify.");
            callId = swnClientForWitness.WitnessrAsyncNotify(pContext);
            BaseTestSite.Assert.AreNotEqual<uint>(0, callId, "WitnessrAsyncNotify returns callId = {0}", callId);

            // NOTICE
            // This comment is for current Windows Cluster test environment.
            // Current test environment has only two nodes and both they are optimum nodes.
            // So whatever the server name is, SHARE_MOVE_NOTIFICATION notification will be recieved.
            // The configuration items 'OptimumNodeOfAsymmetricShare' and 'NonOptimumNodeOfAsymmetricShare' are assigned the same default value.
            // The code in if block will be executed all the time.
            if (serverName == TestConfig.NonOptimumNodeOfAsymmetricShare)
            {
                #region Expect that SHARE_MOVE_NOTIFICATION notification will be received  when the client connects to the asymmetric share on the non-optimum share
                RESP_ASYNC_NOTIFY respNotify;
                ret = swnClientForWitness.ExpectWitnessrAsyncNotify(callId, out respNotify);
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrAsyncNotify returns with result code = 0x{0:x8}", ret);
                SWNTestUtility.PrintNotification(respNotify);
                SWNTestUtility.VerifyClientMoveShareMoveAndIpChange(respNotify, SwnMessageType.SHARE_MOVE_NOTIFICATION, (uint)SwnIPAddrInfoFlags.IPADDR_V4, TestConfig.Platform);

                #region Get the new IpAddr
                IPADDR_INFO_LIST ipAddrInfoList;
                SwnUtility.ParseIPAddrInfoList(respNotify, out ipAddrInfoList);
                currentAccessIp = (ipAddrInfoList.IPAddrList[0].Flags & (uint)SwnNodeFlagsValue.IPv4) != 0 ? new IPAddress(ipAddrInfoList.IPAddrList[0].IPV4) : SWNTestUtility.ConvertIPV6(ipAddrInfoList.IPAddrList[0].IPV6);
                #endregion

                #region Unregister SWN Witness
                BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client calls WitnessrUnRegister.");
                ret = swnClientForWitness.WitnessrUnRegister(pContext);
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrUnRegister returns with result code = 0x{0:x8}", ret);
                pContext = IntPtr.Zero;
                swnClientForWitness.SwnUnbind(TestConfig.Timeout);
                #endregion

                #region Disconnect current SMB2 connection
                BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the client by sending the following requests: TREE_DISCONNECT; LOG_OFF; DISCONNECT.");
                smb2Client.TreeDisconnect(treeId);
                smb2Client.LogOff();
                smb2Client.Disconnect();
                #endregion
                #endregion
            }
            else
            {
                #region Expect that no SHARE_MOVE_NOTIFICATION notification will be received when the client connects to the asymmetric share on the optimum share
                bool isNotificationReceived = false;
                try
                {
                    RESP_ASYNC_NOTIFY respNotify;
                    ret = swnClientForWitness.ExpectWitnessrAsyncNotify(callId, out respNotify);
                    isNotificationReceived = true;
                }
                catch (TimeoutException)
                {
                    isNotificationReceived = false;
                }

                #region Disconnect current SMB2 connection
                BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the second client by sending the following requests: TREE_DISCONNECT; LOG_OFF; DISCONNECT");
                smb2Client.TreeDisconnect(treeId);
                smb2Client.LogOff();
                smb2Client.Disconnect();
                #endregion

                #region Unregister SWN Witness
                BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client calls WitnessrUnRegister.");
                ret = swnClientForWitness.WitnessrUnRegister(pContext);
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrUnRegister returns with result code = 0x{0:x8}", ret);
                pContext = IntPtr.Zero;
                swnClientForWitness.SwnUnbind(TestConfig.Timeout);
                #endregion

                BaseTestSite.Assert.IsFalse(isNotificationReceived, "Expect that no notification will be received when the client has connected to asymmetric share on the optimum node.");
                #endregion

                return;
            }
            #endregion

            #region Connect to the share on the optimum node
            smb2Client = new Smb2FunctionalClient(TestConfig.FailoverTimeout, TestConfig, BaseTestSite);
            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Got the IP {0} to access the file server", currentAccessIp.ToString());

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start a client by sending the following requests: NEGOTIATE; SESSION_SETUP");
            smb2Client.ConnectToServerOverTCP(currentAccessIp);
            smb2Client.Negotiate(
                TestConfig.RequestDialects,
                TestConfig.IsSMB1NegotiateEnabled,
                capabilityValue: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES,
                clientGuid: clientGuid,
                checker: (Packet_Header header, NEGOTIATE_Response response) =>
                {
                    BaseTestSite.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, header.Status, "Negotiate should succeed.");
                });
            smb2Client.SessionSetup(
                TestConfig.DefaultSecurityPackage,
                serverName,
                TestConfig.AccountCredential,
                TestConfig.UseServerGssToken);

            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Client sends TREE_CONNECT and wait for a response until timeout.");
            DoUntilSucceed(
                () => smb2Client.TreeConnect(uncSharePath, out treeId, (header, response) => { }),
                TestConfig.FailoverTimeout,
                "Retry TreeConnect until succeed within timeout span");

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client writes to the file.");
            smb2Client.Create(
                treeId,
                file,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE | CreateOptions_Values.FILE_DELETE_ON_CLOSE,
                out fileId,
                out serverCreateContexts,
                RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE);
            smb2Client.Write(treeId, fileId, content);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client reads from the file.");
            smb2Client.Read(treeId, fileId, 0, (uint)content.Length, out readContent);
            BaseTestSite.Assert.IsTrue(
                content.Equals(readContent),
                "Content read should be identical to that written.");

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the client by sending the following requests: TREE_DISCONNECT; LOG_OFF; DISCONNECT.");
            smb2Client.TreeDisconnect(treeId);
            smb2Client.LogOff();
            smb2Client.Disconnect();
            #endregion
        }
        /// <summary>
        /// SWN client invoke WitnessrGetInterfaceList method to retrieve information about the interfaces to which witness client connections can be made.
        /// </summary>
        /// <param name="InterfaceList">A pointer to a PWITNESS_INTERFACE_LIST, as specified in section 2.2.1.9.</param>
        /// <returns>Return zero if success, otherwise return nonzero.</returns>
        public int WitnessrGetInterfaceList(out WITNESS_INTERFACE_LIST InterfaceList)
        {
            Int3264[] paramList;
            int retVal = 0;

            paramList = new Int3264[] {
                IntPtr.Zero,    //out param
                IntPtr.Zero //return value
            };

            using (RpceInt3264Collection outParamList = RpceCall(paramList, (ushort)SWN_OPNUM.WitnessrGetInterfaceList))
            {
                WITNESS_INTERFACE_LIST_RPC rpcList = TypeMarshal.ToStruct<WITNESS_INTERFACE_LIST_RPC>(Marshal.ReadIntPtr(outParamList[0]));
                WITNESS_INTERFACE_INFO[] infoList = new WITNESS_INTERFACE_INFO[rpcList.NumberOfInterfaces];
                int sizeInByte = Marshal.SizeOf(typeof(WITNESS_INTERFACE_INFO));
                for (int i = 0; i < rpcList.NumberOfInterfaces; i++)
                {
                    IntPtr pInfo = IntPtrUtility.Add(rpcList.InterfaceInfo, i * sizeInByte);
                    infoList[i] = (WITNESS_INTERFACE_INFO)Marshal.PtrToStructure(pInfo, typeof(WITNESS_INTERFACE_INFO));
                }

                InterfaceList = new WITNESS_INTERFACE_LIST();
                InterfaceList.NumberOfInterfaces = rpcList.NumberOfInterfaces;
                InterfaceList.InterfaceInfo = infoList;

                retVal = outParamList[paramList.Length - 1].ToInt32();
            }
            return retVal;
        }