The class provides methods to build the request payload and parse the response payload.
 /// <summary>
 /// Initialize the test suite.
 /// </summary>
 protected override void TestInitialize()
 {
     base.TestInitialize();
     this.adapter           = Site.GetAdapter <IMS_OXCMAPIHTTPAdapter>();
     this.sutControlAdapter = Site.GetAdapter <IMS_OXCMAPIHTTPSUTControlAdapter>();
     this.ropBufferHelper   = new RopBufferHelper(this.Site);
     this.adminUserName     = Common.GetConfigurationPropertyValue("AdminUserName", this.Site);
     this.adminUserPassword = Common.GetConfigurationPropertyValue("AdminUserPassword", this.Site);
     this.adminUserDN       = Common.GetConfigurationPropertyValue("AdminUserEssdn", this.Site);
 }
 /// <summary>
 /// Initialize the test suite.
 /// </summary>
 protected override void TestInitialize()
 {
     base.TestInitialize();
     this.adapter = Site.GetAdapter<IMS_OXCMAPIHTTPAdapter>();
     this.sutControlAdapter = Site.GetAdapter<IMS_OXCMAPIHTTPSUTControlAdapter>();
     this.ropBufferHelper = new RopBufferHelper(this.Site);
     this.adminUserName = Common.GetConfigurationPropertyValue("AdminUserName", this.Site);
     this.adminUserPassword = Common.GetConfigurationPropertyValue("AdminUserPassword", this.Site);
     this.adminUserDN = Common.GetConfigurationPropertyValue("AdminUserEssdn", this.Site);
 }
        public void MSOXCMAPIHTTP_S01_TC08_ExecuteRequestType()
        {
            this.CheckMapiHttpIsSupported();
            WebHeaderCollection headers = new WebHeaderCollection();

            #region Send a valid Connect request type to establish a Session Context with the server.
            ConnectSuccessResponseBody connectResponse = this.ConnectToServer(out headers);
            Site.Assert.AreEqual<uint>(0, connectResponse.StatusCode, "The server should return a Status 0 in X-ResponseCode header if client connect to server succeeded.");
            #endregion

            #region Send an Execute request that includes Logon ROP to server.
            WebHeaderCollection executeHeaders = AdapterHelper.InitializeHTTPHeader(RequestType.Execute, AdapterHelper.ClientInstance, AdapterHelper.Counter);

            ExecuteRequestBody requestBody = this.InitializeExecuteRequestBody(this.GetRopLogonRequest());
            List<string> metaTags = new List<string>();
            ExecuteSuccessResponseBody executeSuccessResponse = this.SendExecuteRequest(requestBody, ref executeHeaders, out metaTags) as ExecuteSuccessResponseBody;

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

            // Verify MS-OXCMAPIHTTP requirement: MS-OXCMAPIHTTP_R1134
            // According to the Open Specification, the server must respond immediately to a request while the request is being queued and the initial response includes the PROCESSING meta-tag.
            // So MS-OXCMAPIHTTP_R1134 can be verified if the first meta-tag is PROCESSING.
            this.Site.CaptureRequirementIfAreEqual<string>(
                "PROCESSING",
                metaTags[0],
                1134,
                @"[In Response Meta-Tags] PROCESSING: The server has queued the request to be processed.");

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

            // Verify MS-OXCMAPIHTTP requirement: MS-OXCMAPIHTTP_R1136
            // According to the Open Specification, the final response must include the DONE meta-tag. And the response body is parsed according to the description of this requirement.
            // So if the last meta-tag is DONE and code can reach here, MS-OXCMAPIHTTP_R1136 can be verified.
            this.Site.CaptureRequirementIfAreEqual<string>(
                "DONE",
                metaTags[metaTags.Count - 1],
                1136,
                @"[In Response Meta-Tags] DONE: The server has completed the processing of the request and additional response headers and the response body follow the DONE meta-tag.");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMAPIHTTP_R1266. The header value of Transfer-Encoding is {0} and Content-Length is {1}.", executeHeaders["Transfer-Encoding"], executeHeaders["Content-Length"]);

            // Verify MS-OXCMAPIHTTP requirement: MS-OXCMAPIHTTP_R1266
            bool isVerifiedR1266 = string.IsNullOrEmpty(executeHeaders["Content-Length"]) && executeHeaders["Transfer-Encoding"].ToLower() == "chunked".ToLower();

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR1266,
                2227,
                @"[In Responding to All Request Type Requests] If the server is using the ""chunked"" transfer coding, it MUST flush this to the client (being careful to make sure it disables any internal Nagle algorithms, as described in [RFC896], that might attempt to buffer response data).");

            // Add the debug information
            this.Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-OXCMAPIHTTP_R1230. The first meta-Tag is {0}, the value of header Transfer-Encoding is {1}.",
                metaTags[0],
                executeHeaders["Transfer-Encoding"]);

            // Verify MS-OXCMAPIHTTP requirement: MS-OXCMAPIHTTP_R1230
            // Because the server will spend some time to process the Logon request. So the entire response is not readily available.
            // The first meta tag is not "DONE" indicates the server is processing the request and not done.
            bool isVerifiedR1230 = metaTags[0] != "DONE" && executeHeaders["Transfer-Encoding"].ToLower() == "chunked".ToLower();

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR1230,
                1230,
                @"[In Responding to All Request Type Requests] If the entire response is not readily available, the server MUST use the Transfer-Encoding header, as specified in section 2.2.3.2.5, with a value of ""chunked"".");
            
            // R1230 ensures that the "chunked" transfer encoding is used and server can return data to the client while the request is still being processed.
            this.Site.CaptureRequirement(
                1174,
                @"[In Handling a Chunked Response] By using ""chunked"" transfer encoding, the server is able to return data to the client while the request is still being processed.");

            // R1230 ensures that the "chunked" transfer encoding is used and a positive connection between the server and client is established.
            this.Site.CaptureRequirement(
                1173,
                @"[In Handling a Chunked Response] To facilitate a positive connection between the server and client, the server uses the Transfer-Encoding header, as specified in section 2.2.3.2.5, with ""chunked"" transfer encoding, as specified in [RFC2616].");

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

            // Verify MS-OXCMAPIHTTP requirement: MS-OXCMAPIHTTP_R1244
            // The X-ResponseCode header is parsed after the DONE meta-tag, and Execute request type response body is parsed after the header X-ResponseCode. 
            // So if the last meta-tag is DONE and code can reach here, this requirement can be verified.
            this.Site.CaptureRequirementIfAreEqual<string>(
                metaTags[metaTags.Count - 1],
                "DONE",
                1244,
                @"[In Responding to All Request Type Requests] After the server finishes processing the request it finishes with the DONE meta-tag, as specified in section 2.2.7; followed by any additional response headers.");

            #endregion
            #endregion

            #region Send an Execute request to open one folder to check the logon operation succeeds.
            RPC_HEADER_EXT[] rpcHeaderExts;
            byte[][] rops;
            uint[][] serverHandleObjectsTables;

            RopBufferHelper ropBufferHelper = new RopBufferHelper(Site);
            ropBufferHelper.ParseResponseBuffer(executeSuccessResponse.RopBuffer, out rpcHeaderExts, out rops, out serverHandleObjectsTables);
            RopLogonResponse logonResponse = new RopLogonResponse();
            logonResponse.Deserialize(rops[0], 0);
            uint logonHandle = serverHandleObjectsTables[0][logonResponse.OutputHandleIndex];

            RopOpenFolderRequest openFolderRequest = this.OpenFolderRequest(logonResponse.FolderIds[4]);

            ExecuteRequestBody openFolderRequestBody = this.InitializeExecuteRequestBody(openFolderRequest, logonHandle);
            executeHeaders = AdapterHelper.InitializeHTTPHeader(RequestType.Execute, AdapterHelper.ClientInstance, AdapterHelper.Counter);
            executeSuccessResponse = this.SendExecuteRequest(openFolderRequestBody, ref executeHeaders, out metaTags) as ExecuteSuccessResponseBody;

            Site.Assert.AreEqual<uint>((uint)0, executeSuccessResponse.StatusCode, "Execute method should succeed.");
            ropBufferHelper.ParseResponseBuffer(executeSuccessResponse.RopBuffer, out rpcHeaderExts, out rops, out serverHandleObjectsTables);
            RopOpenFolderResponse openFolderResponse = new RopOpenFolderResponse();
            openFolderResponse.Deserialize(rops[0], 0);

            // Add the debug information
            this.Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-OXCMAPIHTTP_R226. The error code of Execute request type is {0}, the return value of RopOpenFolder is {1}.",
                executeSuccessResponse.ErrorCode,
                openFolderResponse.ReturnValue);

            // Verify MS-OXCMAPIHTTP requirement: MS-OXCMAPIHTTP_R226
            // If the return value of RopOpenFolder is 0, it indicates that the Logon handle is valid, so the Execute request type can be used to send the remote operation requests.
            bool isVerifiedR226 = executeSuccessResponse.ErrorCode == 0 && openFolderResponse.ReturnValue == 0;

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR226,
                226,
                @"[In Execute Request Type] The Execute request type is used by the client to send remote operation requests to the server.");
            #endregion

            #region Send a Disconnect request to destroy the Session Context.
            MailboxResponseBodyBase response;
            this.Adapter.Disconnect(out response);
            #endregion
        }
        /// <summary>
        /// Clean up the test.
        /// </summary>
        protected override void TestCleanup()
        {
            if (this.isReceiveNewMail == true)
            {
                WebHeaderCollection headers = new WebHeaderCollection();
                MailboxResponseBodyBase response;

                #region Send a valid Connect request type to establish a Session Context with the server.
                ConnectSuccessResponseBody connectResponse = this.ConnectToServer(out headers);
                #endregion

                #region Send an Execute request that incluldes Logon ROP to server.
                WebHeaderCollection executeHeaders = AdapterHelper.InitializeHTTPHeader(RequestType.Execute, AdapterHelper.ClientInstance, AdapterHelper.Counter);

                ExecuteRequestBody requestBody = this.InitializeExecuteRequestBody(this.GetRopLogonRequest());
                List<string> metaTags = new List<string>();

                ExecuteSuccessResponseBody executeSuccessResponse = this.SendExecuteRequest(requestBody, ref executeHeaders, out metaTags) as ExecuteSuccessResponseBody;

                ulong folderId;
                RopLogonResponse logonResponse = new RopLogonResponse();
                uint logonHandle = this.ParseLogonResponse(executeSuccessResponse.RopBuffer, out folderId, out logonResponse);
                #endregion

                #region Send an Execute request to open inbox folder.
                RPC_HEADER_EXT[] rpcHeaderExts;
                byte[][] rops;
                uint[][] serverHandleObjectsTables;
                RopOpenFolderRequest openFolderRequest = this.OpenFolderRequest(logonResponse.FolderIds[4]);

                ExecuteRequestBody openFolderRequestBody = this.InitializeExecuteRequestBody(openFolderRequest, logonHandle);
                executeHeaders = AdapterHelper.InitializeHTTPHeader(RequestType.Execute, AdapterHelper.ClientInstance, AdapterHelper.Counter);
                executeSuccessResponse = this.SendExecuteRequest(openFolderRequestBody, ref executeHeaders, out metaTags) as ExecuteSuccessResponseBody;

                RopBufferHelper ropBufferHelper = new RopBufferHelper(Site);
                ropBufferHelper.ParseResponseBuffer(executeSuccessResponse.RopBuffer, out rpcHeaderExts, out rops, out serverHandleObjectsTables);
                RopOpenFolderResponse openFolderResponse = new RopOpenFolderResponse();
                openFolderResponse.Deserialize(rops[0], 0);
                 uint folderHandle = serverHandleObjectsTables[0][openFolderResponse.OutputHandleIndex];
                #endregion

                #region Send an Execute request type to hard delete messages in inbox folder.
                RopHardDeleteMessagesAndSubfoldersRequest hardDeleteRequest;
                hardDeleteRequest.RopId = (byte)RopId.RopHardDeleteMessagesAndSubfolders;
                hardDeleteRequest.LogonId = ConstValues.LogonId;

                // Set InputHandleIndex to 0x00, which specifies the location in the Server object handle table
                // where the handle for the input Server object is stored.
                hardDeleteRequest.InputHandleIndex = 0;
                hardDeleteRequest.WantAsynchronous = 0x00; // Synchronously
                hardDeleteRequest.WantDeleteAssociated = 0xFF; // TRUE: delete all messages and subfolders
                ExecuteRequestBody hardDeleteRequestBody = this.InitializeExecuteRequestBody(hardDeleteRequest, folderHandle);
                executeHeaders = AdapterHelper.InitializeHTTPHeader(RequestType.Execute, AdapterHelper.ClientInstance, AdapterHelper.Counter);
                executeSuccessResponse = this.SendExecuteRequest(hardDeleteRequestBody, ref executeHeaders, out metaTags) as ExecuteSuccessResponseBody;
                RopHardDeleteMessagesAndSubfoldersResponse hardDeleteMessagesAndSubfoldersResponse = new RopHardDeleteMessagesAndSubfoldersResponse();
                hardDeleteMessagesAndSubfoldersResponse.Deserialize(rops[0], 0);
                #endregion

                #region Send an Execute request to open sent items folder.
                openFolderRequest = this.OpenFolderRequest(logonResponse.FolderIds[6]);

                openFolderRequestBody = this.InitializeExecuteRequestBody(openFolderRequest, logonHandle);
                executeHeaders = AdapterHelper.InitializeHTTPHeader(RequestType.Execute, AdapterHelper.ClientInstance, AdapterHelper.Counter);
                executeSuccessResponse = this.SendExecuteRequest(openFolderRequestBody, ref executeHeaders, out metaTags) as ExecuteSuccessResponseBody;

                ropBufferHelper = new RopBufferHelper(Site);
                ropBufferHelper.ParseResponseBuffer(executeSuccessResponse.RopBuffer, out rpcHeaderExts, out rops, out serverHandleObjectsTables);
                openFolderResponse = new RopOpenFolderResponse();
                openFolderResponse.Deserialize(rops[0], 0);
                folderHandle = serverHandleObjectsTables[0][openFolderResponse.OutputHandleIndex];
                #endregion

                #region Send an Execute request type to hard delete messages in sent items folder.
                hardDeleteRequest.RopId = (byte)RopId.RopHardDeleteMessagesAndSubfolders;
                hardDeleteRequest.LogonId = ConstValues.LogonId;

                // Set InputHandleIndex to 0x00, which specifies the location in the Server object handle table
                // where the handle for the input Server object is stored.
                hardDeleteRequest.InputHandleIndex = 0;
                hardDeleteRequest.WantAsynchronous = 0x00; // Synchronously
                hardDeleteRequest.WantDeleteAssociated = 0xFF; // TRUE: delete all messages and subfolders
                hardDeleteRequestBody = this.InitializeExecuteRequestBody(hardDeleteRequest, folderHandle);
                executeHeaders = AdapterHelper.InitializeHTTPHeader(RequestType.Execute, AdapterHelper.ClientInstance, AdapterHelper.Counter);
                executeSuccessResponse = this.SendExecuteRequest(hardDeleteRequestBody, ref executeHeaders, out metaTags) as ExecuteSuccessResponseBody;
                hardDeleteMessagesAndSubfoldersResponse = new RopHardDeleteMessagesAndSubfoldersResponse();
                hardDeleteMessagesAndSubfoldersResponse.Deserialize(rops[0], 0);
                #endregion

                #region Send a Disconnect request to destroy the Session Context.
                this.Adapter.Disconnect(out response);
                #endregion

                this.isReceiveNewMail = false;
            }

            base.TestCleanup();
        }