Microsoft.Protocols.TestSuites.MS_OXCSTOR.S03_SyncUpReadAndUnreadInformation.MSOXCSTOR_S03_TC04_WritePerUserInformationForPrivateLogon C# (CSharp) Method

MSOXCSTOR_S03_TC04_WritePerUserInformationForPrivateLogon() private method

        public void MSOXCSTOR_S03_TC04_WritePerUserInformationForPrivateLogon()
        {
            this.CheckTransportIsSupported();

            #region Variable
            ushort maxDataSize = 4096;
            ushort defaultDataSize = 4096;

            IDSETWithReplGuid validIdset = this.GenerateRandomValidIdset();
            LongTermId longTermIdForValidData;
            LongTermId longTermIdForInValidData;
            #endregion

            #region Step 1: Connect and log on to a public folder
            this.returnStatus = this.oxcstorAdapter.ConnectEx(ConnectionType.PublicFolderServer);
            Site.Assert.IsTrue(this.returnStatus, "Connection is successful");

            this.oxcstorAdapter.DoRopCall(this.logonRequestForPublicFolder, this.insideObjHandle, ROPCommandType.RopLogonPublicFolder, out this.outputBuffer);
            this.logonResponse = (RopLogonResponse)this.outputBuffer.RopsList[0];
            Site.Assert.AreEqual<uint>(0, this.logonResponse.ReturnValue, "0 indicates the ROP succeeds, other value indicates error occurs.");
            this.outObjHandle = this.outputBuffer.ServerObjectHandleTable[0];

            // Get LongTermID of the folder[1], used in below RopRead/WritePerUserInformation request with valid data
            longTermIdForValidData = this.GetLongTermIdFromId(this.logonResponse.FolderIds[1]);

            validIdset.ReplGuid = longTermIdForValidData.DatabaseGuid;

            // Get LongTermID of the folder[2], used in below RopRead/WritePerUserInformation request with invalid data
            longTermIdForInValidData = this.GetLongTermIdFromId(this.logonResponse.FolderIds[2]);
            #endregion

            #region Step 2: Disconnect.
            this.returnStatus = this.oxcstorAdapter.DisconnectEx();
            this.Site.Assert.IsTrue(this.returnStatus, "Disconnect successfully.");
            #endregion

            #region Step 3: Connect and log on to a private mailbox.
            this.returnStatus = this.oxcstorAdapter.ConnectEx(ConnectionType.PrivateMailboxServer);
            this.oxcstorAdapter.DoRopCall(this.logonRequestForPrivateMailBox, this.insideObjHandle, ROPCommandType.RopLogonPrivateMailbox, out this.outputBuffer);
            this.logonResponse = (RopLogonResponse)this.outputBuffer.RopsList[0];

            this.outObjHandle = this.outputBuffer.ServerObjectHandleTable[0];
            Site.Assert.AreEqual<uint>(
                0,
                this.logonResponse.ReturnValue,
                "0 indicates the ROP succeeds, other value indicates error occurs.");
            #endregion

            #region Step 4: Call WritePerUserInformationRequest to write invalid data with HasFinished field set to false, so the server will cache these data.

            byte[] data = new byte[5000];
            this.writePerUserInformationRequest.FolderId = longTermIdForInValidData;
            this.writePerUserInformationRequest.DataSize = (ushort)data.Length;
            this.writePerUserInformationRequest.Data = data;
            this.writePerUserInformationRequest.ReplGuid = this.logonResponse.ReplGuid;
            this.writePerUserInformationRequest.HasFinished = 0x01;
            this.writePerUserInformationRequest.DataOffset = 0;
            this.oxcstorAdapter.DoRopCall(this.writePerUserInformationRequest, this.outObjHandle, ROPCommandType.RopWritePerUserInformation, out this.outputBuffer);
            this.writePerUserInformationResponse = (RopWritePerUserInformationResponse)this.outputBuffer.RopsList[0];
            if (this.writePerUserInformationResponse.ReturnValue == 0x8004011B)
            {
                IDSETWithReplGuid validIdset1 = this.GenerateRandomValidIdset(true);
                byte[] validDataForWrite1 = validIdset1.Serialize();
                this.writePerUserInformationRequest.DataSize = (ushort)(validDataForWrite1.Length);
                this.writePerUserInformationRequest.Data = validDataForWrite1;
                this.oxcstorAdapter.DoRopCall(this.writePerUserInformationRequest, this.outObjHandle, ROPCommandType.RopWritePerUserInformation, out this.outputBuffer);
                this.writePerUserInformationResponse = (RopWritePerUserInformationResponse)this.outputBuffer.RopsList[0];
            }

            this.writePerUserInformationRequest.HasFinished = 0x00;
            this.oxcstorAdapter.DoRopCall(this.writePerUserInformationRequest, this.outObjHandle, ROPCommandType.RopWritePerUserInformation, out this.outputBuffer);
            this.writePerUserInformationResponse = (RopWritePerUserInformationResponse)this.outputBuffer.RopsList[0];

            Site.Assert.AreEqual<uint>(
                0,
                this.writePerUserInformationResponse.ReturnValue,
                "0 indicates the ROP succeeds, other value indicates error occurs.");
            #endregion

            #region Step 5: Call RopReadPerUserInformation with MaxDataSize set to 4097.
            ushort bigerMaxDateSize = (ushort)(maxDataSize + 1);
            this.readPerUserInformationRequest.Reserved = 0x00;
            this.readPerUserInformationRequest.FolderId = longTermIdForInValidData;
            this.readPerUserInformationRequest.MaxDataSize = bigerMaxDateSize;
            this.oxcstorAdapter.DoRopCall(this.readPerUserInformationRequest, this.outObjHandle, ROPCommandType.RopReadPerUserInformation, out this.outputBuffer);
            this.readPerUserInformationResponse = (RopReadPerUserInformationResponse)this.outputBuffer.RopsList[0];

            #region Capture
            if (Common.IsRequirementEnabled(999, this.Site))
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R999");

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R999.
                Site.CaptureRequirementIfAreEqual<ushort>(
                    maxDataSize,
                    this.readPerUserInformationResponse.DataSize,
                    999,
                    @"[In Appendix A: Product Behavior] Implementation's maximum value of MaxDataSize is 4096. (If MaxDataSize > [server's suitable maximum (4096)], then Implementation does adjust the value of MaxDataSize to the suitable maximum value (4096) in Microsoft Exchanges. <48> Section 3.2.5.12.1: Exchange 2003, Exchange 2007, Exchange 2010, Exchange 2013 and Exchange 2016 use 4096 for the maximum value.)");
            }
            #endregion

            #region Capture
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R979");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R979.
            Site.CaptureRequirementIfAreEqual<ushort>(
                maxDataSize,
                (ushort)this.readPerUserInformationResponse.Data.Length,
                979,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] On each invocation of RopReadPerUserInformation, the server inspects the value of the MaxDataSize field of the RopReadPerUserInformation request because the value can be different in each request.");

            if (Common.IsRequirementEnabled(997, this.Site))
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R997");

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R997.
                Site.CaptureRequirementIfAreEqual<ushort>(
                    maxDataSize,
                    (ushort)this.readPerUserInformationResponse.Data.Length,
                    997,
                    @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] Implementation does compare the value of MaxDataSize to some suitable maximum value (4096), as determined by the implementation in Microsoft Exchanges. (Exchange 2003 and above follow this behavior.)");
            }

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R981");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R981
            // Write the data with 5000 bytes to the server, and pass 4097 to the MaxDataSize field of RopReadPerUserInformation ROP request,
            // because 4097<5000, so the server will adjust the value of MaxDataSize to 4096. 
            // Thus, if check the length of the obtained data is not equal to 4097 that set, it indicates that the server adjusted the value of MaxDataSize.
            Site.CaptureRequirementIfAreNotEqual<ushort>(
                bigerMaxDateSize,
                (ushort)this.readPerUserInformationResponse.Data.Length,
                981,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] After the server has inspected and, if necessary, adjusted the value of MaxDataSize, the server compares the value to the size of the remaining BLOB segment.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R988");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R988.
            // MS-OXCSTOR_R981 has verified the server adjusted the value of MaxDataSize, MS-OXCSTOR_R988 can be verified directly.
            Site.CaptureRequirement(
                988,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The server MUST adjust the MaxDataSize value in certain cases, as specified in item 2[When the client retrieves a BLOB in segments, the client can set MaxDataSize to a different value in each RopReadPerUserInformation request that is used to retrieve the BLOB.] of this summary.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R982");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R982.
            Site.CaptureRequirementIfAreEqual<byte>(
                0,
                this.readPerUserInformationResponse.HasFinished,
                982,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] If the adjusted MaxDataSize value is less than the size of the remaining BLOB segment, then the server MUST set HasFinished field to FALSE to indicate to the client that some data remains to be retrieved.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R990");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R990
            // If the MaxDataSize is changed by the server, it indicates server inspect the value of MaxDataSize.
            Site.CaptureRequirementIfAreNotEqual<ushort>(
                bigerMaxDateSize,
                (ushort)this.readPerUserInformationResponse.Data.Length,
                990,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] [When the client retrieves a BLOB in segments, the client can set MaxDataSize to a different value in each RopReadPerUserInformation request that is used to retrieve the BLOB]Therefore, the server examines the value of MaxDataSize on each invocation of RopReadPerUserInformation as follows.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R1001");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1001
            // First write the data with 5000 bytes, and the Exchange (all versions) uses 4096 for the maximum value to make
            // [size of remaining BLOB segment] > [adjusted MaxDataSize](4096). 
            // Then if the HasFinished is set to FALSE, this Requirement is verified.
            Site.CaptureRequirementIfAreEqual<byte>(
                0,
                this.readPerUserInformationResponse.HasFinished,
                1001,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] If [size of remaining BLOB segment] > [adjusted MaxDataSize], then the server MUST set HasFinished to FALSE to indicate to the client that additional requests are necessary to retrieve all of the remaining portions of the BLOB.");

            #endregion
            #endregion

            #region Step 6: Call RopReadPerUserInformation with MaxDataSize set to 0.
            this.readPerUserInformationRequest.MaxDataSize = 0;
            this.oxcstorAdapter.DoRopCall(this.readPerUserInformationRequest, this.outObjHandle, ROPCommandType.RopReadPerUserInformation, out this.outputBuffer);
            this.readPerUserInformationResponse = (RopReadPerUserInformationResponse)this.outputBuffer.RopsList[0];
            byte[] userInformation1 = this.readPerUserInformationResponse.Data;

            #region Capture
            if (Common.IsRequirementEnabled(1356, this.Site))
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R1356");

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1356.
                Site.CaptureRequirementIfAreEqual<ushort?>(
                    defaultDataSize,
                    this.readPerUserInformationResponse.DataSize,
                    1356,
                    @"[In Appendix A: Product Behavior] Implementation's default value of MaxDataSize is 4096. (If MaxDataSize equals 0, then the server MUST adjust the value of MaxDataSize to a suitable default value (4096). <47> Section 3.2.5.12.1: Exchange 2003, Exchange 2007, Exchange 2010, Exchange 2013, and Exchange 2016 use 4096 for the default value.)");
            }
            #endregion

            #region Capture
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R980");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R980
            // At step14, request with MaxDataSize=0 when Blob segment in server is greater than MaxDataSize
            // So if the response data size is equal to MaxDataSize, then could verify this requirement.
            Site.CaptureRequirementIfAreNotEqual<ushort>(
                0,
                (ushort)this.readPerUserInformationResponse.DataSize,
                980,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] In certain cases [if MaxDataSize equals 0], the server MUST adjust the value of MaxDataSize.");

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-OXCSTOR_R1004,
                the value of DataSize is {0},
                the adjusted value of the MaxDataSize field is {1}.",
                this.readPerUserInformationResponse.DataSize,
                defaultDataSize);

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1004
            // request with MaxDataSize=0, server will adjust the MaxDataSize to default suitable MaxDataSize (4096)
            // Verify the returned data size does not exceed the 4096
            bool isVerifiedR1004 = this.readPerUserInformationResponse.DataSize <= maxDataSize;

            Site.CaptureRequirementIfIsTrue(
                isVerifiedR1004,
                1004,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The value of DataSize MUST NOT exceed the adjusted value of the MaxDataSize field.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R991");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R991
            // At step14, MaxDataSize=0 in the RopReadPerUserInformation ROP request,
            // but the data returned is not null. It indicates the MaxDataSize is changed by the server. 
            // So, the server must compare the value of MaxDataSize to zero.
            Site.CaptureRequirementIfAreNotEqual<int>(
                0,
                this.readPerUserInformationResponse.Data.Length,
                991,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The server compares the value of MaxDataSize to zero.");
            #endregion

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R976");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R976.
            // The size of the BLOB is 5000 which exceed the maximum amount of data (4096) that can be communicated in a single RopReadPerUserInformation response.
            // The ROP performs successfully, MS-OXCSTOR_R976 can be verified.
            Site.CaptureRequirementIfAreEqual<uint>(
                0,
                this.readPerUserInformationResponse.ReturnValue,
                976,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The size of the BLOB can potentially exceed the maximum amount of data that can be communicated in a single RopReadPerUserInformation response (section 2.2.1.12.2).");

            #endregion

            #region Step 7: Call RopReadPerUserInformation with DataOffset field based on the number of bytes received in the previous response and MaxDataSize field set to zero.
            this.readPerUserInformationRequest.MaxDataSize = 0;
            this.readPerUserInformationRequest.DataOffset = (uint)userInformation1.Length;
            this.oxcstorAdapter.DoRopCall(this.readPerUserInformationRequest, this.outObjHandle, ROPCommandType.RopReadPerUserInformation, out this.outputBuffer);
            this.readPerUserInformationResponse = (RopReadPerUserInformationResponse)this.outputBuffer.RopsList[0];
            Site.Assert.AreEqual<uint>(0, this.readPerUserInformationResponse.ReturnValue, "0 indicates the ROP succeeds, other value indicates error occurs.");
            byte[] userInformation2 = this.readPerUserInformationResponse.Data;

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R977");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R977.
            // The RopReadPerUserInformation was called twice to get the data which exceed the maximum amount of data that can be communicated in a single RopReadPerUserInformation response, MS-OXCSTOR_R977 can be verified.
            Site.CaptureRequirementIfIsTrue(
                userInformation1.Length + userInformation2.Length > maxDataSize,
                977,
                "[In Behavior Common to Both Private Mailbox and Public Folder Logon] For this reason [the size of the BLOB can potentially exceed the maximum amount of data that can be communicated in a single RopReadPerUserInformation response], the RopReadPerUserInformation ROP ([MS-OXCROPS] section 2.2.3.12) is designed to stream the data to the client by having the client invoke the ROP multiple times.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R986");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R986.
            // Set the DataOffset field of the second RopReadPerUserInformation based on the Data length of the first RopReadPerUserInformation, and the entire BLOB data was got successfully, MS-OXCSTOR_R986 can be verified directly.
            Site.CaptureRequirement(
                986,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The client updates DataOffset based on the number of bytes received in the previous response so that DataOffset always points to the first byte of the next BLOB segment to be returned.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R984");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R984.
            // Set the DataOffset field of the second RopReadPerUserInformation based on the Data length of the first RopReadPerUserInformation, and the entire BLOB data was get successfully, MS-OXCSTOR_R984 can be verified directly.
            Site.CaptureRequirement(
                984,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] In other words, the value of DataOffset specifies the position within the BLOB of the first byte of data to be returned to the client.");
            #endregion

            #region Step 8: Call RopWritePerUserInformation to write subpart user information (all the data of user information except the last byte).
            byte[] dataForWrite = validIdset.Serialize();
            this.writePerUserInformationRequest.FolderId = longTermIdForValidData;
            this.writePerUserInformationRequest.Data = dataForWrite;
            this.writePerUserInformationRequest.DataSize = (ushort)(dataForWrite.Length - 1);
            this.writePerUserInformationRequest.ReplGuid = this.logonResponse.ReplGuid;
            this.writePerUserInformationRequest.DataOffset = 0;
            this.writePerUserInformationRequest.HasFinished = 0x00;
            byte[] dataHasBeenWritten = new byte[dataForWrite.Length - 1];
            Array.Copy(dataForWrite, dataHasBeenWritten, dataHasBeenWritten.Length);

            this.oxcstorAdapter.DoRopCall(this.writePerUserInformationRequest, this.outObjHandle, ROPCommandType.RopWritePerUserInformation, out this.outputBuffer);
            this.writePerUserInformationResponse = (RopWritePerUserInformationResponse)this.outputBuffer.RopsList[0];

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R597");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R597.
            Site.CaptureRequirementIfAreEqual<uint>(
                0,
                this.writePerUserInformationResponse.ReturnValue,
                597,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The error code ecNone: Its value is 0x00000000.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R598");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R598.
            Site.CaptureRequirementIfAreEqual<uint>(
                0,
                this.writePerUserInformationResponse.ReturnValue,
                598,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The error code ecNone: Success.");
            #endregion

            #region Step 9: Call RopWritePerUserInformation to write the last byte of the user information to another public folder.
            // Get the last byte for write. This is the next write-ROP which will write the last byte of data
            // (the former part of  data has been written at former write-ROP at step16
            byte[] lastByteForWrite = new byte[1];
            this.writePerUserInformationRequest.FolderId = longTermIdForInValidData;
            lastByteForWrite[0] = dataForWrite[dataForWrite.Length - 1];
            this.writePerUserInformationRequest.Data = dataForWrite;
            this.writePerUserInformationRequest.DataSize = (ushort)lastByteForWrite.Length;
            this.writePerUserInformationRequest.ReplGuid = this.logonResponse.ReplGuid;
            this.writePerUserInformationRequest.DataOffset = (ushort)(dataForWrite.Length - 1);
            this.writePerUserInformationRequest.HasFinished = 0x01;
            this.oxcstorAdapter.DoRopCall(this.writePerUserInformationRequest, this.outObjHandle, ROPCommandType.RopWritePerUserInformation, out this.outputBuffer);
            this.writePerUserInformationResponse = (RopWritePerUserInformationResponse)outputBuffer.RopsList[0];

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R601");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R601.
            Site.CaptureRequirementIfAreEqual<uint>(
                0x80004005,
                this.writePerUserInformationResponse.ReturnValue,
                601,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The error code ecError: The FolderId didn't match the value on the previous call, AND THEN DataOffset wasn't zero.");
            #endregion

            #region Step 10: Call RopWritePerUserInformation with the wrong DataOffset to write the last byte of the user information.

            this.writePerUserInformationRequest.FolderId = longTermIdForValidData;
            this.writePerUserInformationRequest.Data = dataForWrite;
            this.writePerUserInformationRequest.DataSize = (ushort)dataForWrite.Length;
            this.writePerUserInformationRequest.ReplGuid = this.logonResponse.ReplGuid;
            this.writePerUserInformationRequest.DataOffset = (uint)(lastByteForWrite.Length + 1);
            this.writePerUserInformationRequest.HasFinished = 0x01;
            this.oxcstorAdapter.DoRopCall(this.writePerUserInformationRequest, this.outObjHandle, ROPCommandType.RopWritePerUserInformation, out this.outputBuffer);
            this.writePerUserInformationResponse = (RopWritePerUserInformationResponse)outputBuffer.RopsList[0];

            #region Capture
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R1019");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1019
            Site.CaptureRequirementIfAreEqual<uint>(
                0x80004005,
                this.writePerUserInformationResponse.ReturnValue,
                1019,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] In addition, if the current invocation's DataOffset isn't zero, the ROP [RopWritePerUserInformation] MUST fail with a ReturnValue of 0x80004005.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R599");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R599
            Site.CaptureRequirementIfAreEqual<uint>(
                0x80004005,
                this.writePerUserInformationResponse.ReturnValue,
                599,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The error code ecError: Its value is 0x80004005.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R600");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R600.
            // MS-OXCSTOR_R599 has captured error code 0x80004005 and the DataOffset didn't match the size of the data written so far, MS-OXCSTOR_R600 can be verified directly.
            Site.CaptureRequirement(
                600,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The error code ecError: The DataOffset didn't match the size of the data written so far, AND THEN DataOffset wasn't zero.");
            #endregion
            #endregion

            #region Step 11: Write the last byte of the user information with the proper DataOffset and folder ID, the ROP expect to be failed because the server assume the previous operation was aborted.
            lastByteForWrite = new byte[1];
            lastByteForWrite[0] = dataForWrite[dataForWrite.Length - 1];
            this.writePerUserInformationRequest.Data = lastByteForWrite;
            this.writePerUserInformationRequest.DataSize = (ushort)lastByteForWrite.Length;
            this.writePerUserInformationRequest.ReplGuid = this.logonResponse.ReplGuid;
            this.writePerUserInformationRequest.DataOffset = (ushort)(dataForWrite.Length - 1);
            this.writePerUserInformationRequest.HasFinished = 0x01;
            this.oxcstorAdapter.DoRopCall(this.writePerUserInformationRequest, this.outObjHandle, ROPCommandType.RopWritePerUserInformation, out this.outputBuffer);
            this.writePerUserInformationResponse = (RopWritePerUserInformationResponse)this.outputBuffer.RopsList[0];

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R1033");

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1033.
            // The previous operation was aborted
            Site.CaptureRequirementIfAreNotEqual<uint>(
                0,
                this.writePerUserInformationResponse.ReturnValue,
                1033,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] If the DataOffset value does not equal the amount of data already written, the server MUST assume the previous operation was aborted.");
            #endregion

            #region Step 12: Rewrite sub-part user information again (all the data of user information except the last byte).
            dataForWrite = validIdset.Serialize();
            this.writePerUserInformationRequest.FolderId = longTermIdForValidData;
            this.writePerUserInformationRequest.Data = dataForWrite;
            this.writePerUserInformationRequest.DataSize = (ushort)(dataForWrite.Length - 1);
            this.writePerUserInformationRequest.ReplGuid = this.logonResponse.ReplGuid;
            this.writePerUserInformationRequest.DataOffset = 0;
            this.writePerUserInformationRequest.HasFinished = 0x00;
            dataHasBeenWritten = new byte[dataForWrite.Length - 1];
            Array.Copy(dataForWrite, dataHasBeenWritten, dataHasBeenWritten.Length);

            this.oxcstorAdapter.DoRopCall(this.writePerUserInformationRequest, this.outObjHandle, ROPCommandType.RopWritePerUserInformation, out this.outputBuffer);
            this.writePerUserInformationResponse = (RopWritePerUserInformationResponse)this.outputBuffer.RopsList[0];
            Site.Assert.AreEqual<uint>(0, this.writePerUserInformationResponse.ReturnValue, "0 indicates the ROP succeeds, other value indicates error occurs.");
            #endregion

            #region Step 13: Continue to write the last byte.
            lastByteForWrite = new byte[1];
            lastByteForWrite[0] = dataForWrite[dataForWrite.Length - 1];
            this.writePerUserInformationRequest.Data = lastByteForWrite;
            this.writePerUserInformationRequest.DataSize = (ushort)lastByteForWrite.Length;
            this.writePerUserInformationRequest.ReplGuid = this.logonResponse.ReplGuid;
            this.writePerUserInformationRequest.DataOffset = (ushort)(dataForWrite.Length - 1);
            this.writePerUserInformationRequest.HasFinished = 0x01;
            this.oxcstorAdapter.DoRopCall(this.writePerUserInformationRequest, this.insideObjHandle, ROPCommandType.RopWritePerUserInformation, out this.outputBuffer);
            this.writePerUserInformationResponse = (RopWritePerUserInformationResponse)this.outputBuffer.RopsList[0];
            Site.Assert.AreEqual<uint>(0, this.writePerUserInformationResponse.ReturnValue, "0 indicates the ROP succeeds, other value indicates error occurs.");
            #endregion

            #region Step 14: Call ReadPerUserInformationRequest to verify the sub-part data saved successfully.
            this.readPerUserInformationRequest.FolderId = longTermIdForValidData;
            this.readPerUserInformationRequest.DataOffset = 0;
            this.readPerUserInformationRequest.MaxDataSize = 0;
            this.oxcstorAdapter.DoRopCall(this.readPerUserInformationRequest, this.outObjHandle, ROPCommandType.RopReadPerUserInformation, out this.outputBuffer);
            this.readPerUserInformationResponse = (RopReadPerUserInformationResponse)this.outputBuffer.RopsList[0];

            Site.Assert.AreEqual<uint>(
                0,
                this.readPerUserInformationResponse.ReturnValue,
                "0 indicates the ROP succeeds, other value indicates error occurs.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R1016");

            bool isR1016Verified = this.ByteArrayEquals(this.readPerUserInformationResponse.Data, dataForWrite);

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1016.
            Site.CaptureRequirementIfIsTrue(
                isR1016Verified,
                1016,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The server determines whether the current invocation is a continuation of a previous invocation by examining the FolderId and DataOffset fields.");
            #endregion
        }
    }