Microsoft.Protocols.TestSuites.MS_OXCNOTIF.S02_SubscribeAndReceiveNotifications.MSOXCNOTIF_S02_TC01_VerifyTableRowAddEventAndCreateTableViewByTableQueryRows C# (CSharp) Method

MSOXCNOTIF_S02_TC01_VerifyTableRowAddEventAndCreateTableViewByTableQueryRows() private method

        public void MSOXCNOTIF_S02_TC01_VerifyTableRowAddEventAndCreateTableViewByTableQueryRows()
        {
            this.CheckWhetherSupportMAPIHTTP();
            this.NotificationInitialize();

            #region Open Inbox folder and get content table of the Inbox folder
            uint inboxTableHandle;
            this.OpenFolder(this.InboxFolderId, out inboxTableHandle);

            // The first content table handle is used to trigger the notification.
            uint contentTableHandle1;

            // The second content table handle is used to get the information from the specified table.
            uint contentTableHandle2 = 0;
            this.GetContentsTable(inboxTableHandle, out contentTableHandle1, false);
            #endregion

            #region Create table view by QueryRows

            // The properties need to be set
            PropertyTag[] tags = new PropertyTag[] { PropertyTags.All[PropertyNames.PidTagFolderId], PropertyTags.All[PropertyNames.PidTagInstanceNum], PropertyTags.All[PropertyNames.PidTagMid] };
            this.SetColumns(contentTableHandle1, tags);

            // Retrieves rows from content table to get the data of 30 rows
            this.QueryRows(contentTableHandle1, 30);
            #endregion

            #region Trigger TableRowAdded event and get notification
            ulong messageId = this.TriggerTableRowAddedEvent();
            IList<IDeserializable> rsp = this.CNOTIFAdapter.GetNotification(true);
            Site.Assert.IsTrue(rsp.Count > 0, "The response should contain notification message.");
            #endregion

            #region Verify notification response for TableRowAdded event
            foreach (IDeserializable response in rsp)
            {
                Site.Assert.IsTrue(response.GetType() == typeof(RopNotifyResponse) || response.GetType() == typeof(RopPendingResponse), "The ROP response type should be RopNotifyResponse or RopPendingResponse.");
                if (response is RopNotifyResponse)
                {
                    RopNotifyResponse notifyResponse = (RopNotifyResponse)response;
                    Site.Assert.AreEqual<NotificationType>(NotificationType.TableModified, notifyResponse.NotificationData.NotificationType, "The notification type for the RopNotify response should be TableModified.");
                    Site.Assert.AreEqual<EventTypeOfTable>(EventTypeOfTable.TableRowAdded, notifyResponse.NotificationData.TableEvent, "The table event type for the RopNotify response should be TableRowAdded.");
                    this.VerifyTableModifyNotificationFlag(notifyResponse);
                    this.VerifyTableRowAddedNotificationElements(notifyResponse);
                    if (notifyResponse.NotificationData.TableRowDataSize != null)
                    {
                        #region Verify the elements TableRowDataSize and TableRowData of the notification response

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

                        // Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R163
                        this.Site.CaptureRequirementIfAreEqual<ushort?>(
                            (ushort)notifyResponse.NotificationData.TableRowData.Length,
                            notifyResponse.NotificationData.TableRowDataSize,
                            163,
                            @"[In NotificationData Structure] TableRowDataSize: An unsigned 16-bit integer that indicates the length of the table row data.");

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

                        // Convert TableRowData to string type.
                        string tableRowDataToString = BitConverter.ToString(notifyResponse.NotificationData.TableRowData);
                        Site.Log.Add(LogEntryKind.Debug, "The table row data is {0}.", tableRowDataToString);

                        // Convert TableRowFolderID to string type.
                        Site.Assert.IsNotNull(notifyResponse.NotificationData.TableRowFolderID, "The TableRowFolderID should not null.");
                        string tableRowFolderIDToString = BitConverter.ToString(BitConverter.GetBytes((ulong)notifyResponse.NotificationData.TableRowFolderID));
                        Site.Log.Add(LogEntryKind.Debug, "The value of TableRowFolderID is {0}.", tableRowFolderIDToString);

                        // Convert TableRowInstance to string type.
                        Site.Assert.IsNotNull(notifyResponse.NotificationData.TableRowInstance, "The TableRowInstance should not null.");
                        string tableRowInstanceToString = BitConverter.ToString(BitConverter.GetBytes((uint)notifyResponse.NotificationData.TableRowInstance));
                        Site.Log.Add(LogEntryKind.Debug, "The value of TableRowInstance is {0}.", tableRowInstanceToString);

                        // Convert TableRowMessageID to string type.
                        Site.Assert.IsNotNull(notifyResponse.NotificationData.TableRowMessageID, "The TableRowMessageID should not null.");
                        string tableRowMessageIDToString = BitConverter.ToString(BitConverter.GetBytes((ulong)notifyResponse.NotificationData.TableRowMessageID));
                        Site.Log.Add(LogEntryKind.Debug, "The value of TableRowMessageID is {0}.", tableRowMessageIDToString);

                        // Check whether TableRowData contains TableRowFolderID, TableRowInstance and TableRowMessageID or not.
                        bool isContained = tableRowDataToString.Contains(tableRowFolderIDToString) &&
                            tableRowDataToString.Contains(tableRowInstanceToString) &&
                            tableRowDataToString.Contains(tableRowMessageIDToString);

                        // Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R166
                        // The added properties values are TableRowFolderID, TableRowInstance and TableRowMessageID. 
                        // So if TableRowData contains the three values, this requirement can be verified.
                        this.Site.CaptureRequirementIfIsTrue(
                            isContained,
                            166,
                            @"[In NotificationData Structure] TableRowData (variable): The table row data, which contains a list of property values in a PropertyRow structure, as specified in [MS-OXCDATA] section 2.8, for the row that was added or modified in the table. ");

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

                        // Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R166001
                        // Because TableRowFolderID, TableRowInstance and TableRowMessageID are added by previous RopSetColumns ROP.
                        // So if TableRowData contains the three values, this requirement can be verified.
                        this.Site.CaptureRequirementIfIsTrue(
                            isContained,
                            166001,
                            @"[In NotificationData Structure] The property values to be included are determined by a previous RopSetColumns ROP, as specified in [MS-OXCTABL] section 2.2.2.2. ");
                        #endregion
                    }

                    #region Get the location of the previous row and the row where the modified row is inserted
                    // Open Inbox folder and get content table of the Inbox folder
                    this.OpenFolder(this.InboxFolderId, out inboxTableHandle);
                    uint tableRowInstanceFromTable;
                    uint insertAfterTableRowInstanceFromTable = 0;
                    this.GetContentsTable(inboxTableHandle, out contentTableHandle2, false);

                    // Create table view by QueryRows
                    this.SetColumns(contentTableHandle2, tags);

                    // Retrieves rows from content table to get the data of 30 rows
                    RopQueryRowsResponse queryResponse = this.QueryRows(contentTableHandle2, 30);

                    // Get the location of the current row in the table
                    RopQueryPositionResponse queryPositionResponse = this.QueryPosition(contentTableHandle2);

                    // Get the location of the previous row in the table
                    tableRowInstanceFromTable = BitConverter.ToUInt32(queryResponse.RowData.PropertyRows[(int)queryPositionResponse.Numerator - 2].PropertyValues[1].Value, 0);

                    // Get the location of the row where the modified row is inserted
                    foreach (PropertyRow row in queryResponse.RowData.PropertyRows)
                    {
                        if (BitConverter.ToUInt64(row.PropertyValues[2].Value, 0) == this.LocatingMessageId)
                        {
                            insertAfterTableRowInstanceFromTable = BitConverter.ToUInt32(row.PropertyValues[1].Value, 0);
                        }
                    }
                    #endregion

                    #region Verify the elements of the notification response
                    // Add the debug information
                    this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCNOTIF_R149");

                    // Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R149
                    this.Site.CaptureRequirementIfAreEqual<uint?>(
                        tableRowInstanceFromTable,
                        notifyResponse.NotificationData.TableRowInstance,
                        149,
                        @"[In NotificationData Structure] TableRowInstance: An identifier of the instance of the previous row in the table.");

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

                    // Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R161
                    this.Site.CaptureRequirementIfAreEqual<uint?>(
                        insertAfterTableRowInstanceFromTable,
                        notifyResponse.NotificationData.InsertAfterTableRowInstance,
                        161,
                        @"[In NotificationData Structure] InsertAfterTableRowInstance: An unsigned 32-bit identifier of the instance of the row where the modified row is inserted");

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

                    // Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R161002
                    this.Site.CaptureRequirementIfIsTrue(
                        notifyResponse.NotificationData.InsertAfterTableRowInstance!=null && (notifyResponse.NotificationData.NotificationFlags & 0x8000) == 0x8000 && notifyResponse.NotificationData.TableEventType== 0x0003,
                        161002,
                        @"[In NotificationData Structure] This field [InsertAfterTableRowInstance] is available when bit 0x8000 is set in the NotificationFlags field and if the TableEventType field is available and is 0x0003.");


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

                    // Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R145
                    // If the value of TableRowMessageID is the message which trigger the notification, this requirement can be verified.
                    this.Site.CaptureRequirementIfAreEqual<ulong?>(
                        messageId,
                        notifyResponse.NotificationData.TableRowMessageID,
                        145,
                        @"[In NotificationData Structure] TableRowMessageID: The value of the Message ID structure, as specified in [MS-OXCDATA] section 2.2.1.2, of the item triggering the notification.");

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

                    // Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R141
                    // If the value of TableRowFolderID is the folder which trigger the notification, this requirement can be verified.
                    this.Site.CaptureRequirementIfAreEqual<ulong?>(
                        this.InboxFolderId,
                        notifyResponse.NotificationData.TableRowFolderID,
                        141,
                        @"[In NotificationData Structure] TableRowFolderID: The value of the Folder ID structure, as specified in [MS-OXCDATA] section 2.2.1.1, of the item triggering the notification.");

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

                    // Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R97
                    this.Site.CaptureRequirementIfAreEqual<uint>(
                        contentTableHandle1,
                        notifyResponse.NotificationHandle,
                        97,
                        @"[In RopNotify ROP Response Buffer] [NotificationHandle] The target object can be a table.");

                    // Add the debug information
                    this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCNOTIF_R261: The value of the Folder ID and Message ID separately are {0},{1}", notifyResponse.NotificationData.TableRowFolderID, notifyResponse.NotificationData.TableRowMessageID);

                    // Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R261
                    bool isVerifiedR261 = notifyResponse.NotificationData.TableRowFolderID != null && notifyResponse.NotificationData.TableRowMessageID != null;

                    this.Site.CaptureRequirementIfIsTrue(
                        isVerifiedR261,
                        261,
                        @"[In Creating and Sending TableModified Event Notifications] [When a TableModified event occurs, the server generates a notification using one of the following three methods, listed in descending order of usefulness to the client.] For TableRowAdded event, the server generates an informative notification that specifies the nature of the change (content or hierarchy), the value of the Folder ID structure, as specified in [MS-OXCDATA] section 2.2.1.1, the value of the Message ID structure, as specified in [MS-OXCDATA] section 2.2.1.2, and new table values.");

                    this.VeriyServerGenerateInformativeNotification(isVerifiedR261);

                    Site.Assert.IsNotNull(notifyResponse.NotificationData.TableEventType, "The TableEventType in the RopNotifyResponse should not null.");

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

                    // Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R129
                    this.Site.CaptureRequirementIfAreEqual<int>(
                        0x0003,
                        (int)notifyResponse.NotificationData.TableEventType,
                        129,
                        @"[In NotificationData Structure] [TableEventType value] 0x0003: The notification is for TableRowAdded events.");

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

                    // Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R23
                    // The client can receive TableRowAdded notification indicates that a new row has been added to the table.
                    this.Site.CaptureRequirementIfAreEqual<int>(
                        0x0003,
                        (int)notifyResponse.NotificationData.TableEventType,
                        23,
                        @"[In TableModified Event Types] TableRowAdded: A new row has been added to the table.");

                    // Only Exchange 2010 and above require a table view, this server version restrict of MS-OXCNTOIF_R249 is the same with MS-OXCNTOIF_R245.
                    if (Common.IsRequirementEnabled(245, this.Site))
                    {
                        // Add the debug information
                        Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCNOTIF_R252");

                        // If the server can return notification response, it can verify RopQueryRows create a table view. so the following requirements can be captured directly. 
                        Site.CaptureRequirement(
                            252,
                            @"[In Creating and Sending TableModified Event Notifications] If a table view is required on the server, the server MUST receive a request from one of the following ROPs, each of which cause a table view to be created on the server: RopQueryRows ([MS-OXCROPS] section 2.2.5.4).");

                        this.VerifyTableViewCreated();
                    }
                    #endregion
                }
            }
            #endregion

            // Only Exchange 2010 and above will stop sending notifications if the RopResetTable ROP is received, until a new table view is created.
            if (Common.IsRequirementEnabled(281, this.Site))
            {
                #region Reset the contents table
                // Reset the first content table handle is used to trigger the notification.
                this.ResetTable(contentTableHandle1);

                // Reset the second content table handle is used to get the information from the specified table.
                this.ResetTable(contentTableHandle2);
                #endregion

                #region Trigger TableRowAdded event after ResetTable and get notification
                this.TriggerTableRowAddedEvent();

                // Trigger table event after ResetTable, server shouldn't send notification response on Exchange server 2010 and above
                rsp = this.CNOTIFAdapter.GetNotification(false);
                bool isServerCreateSubscription = false;
                foreach (IDeserializable response in rsp)
                {
                    Site.Assert.IsTrue(response.GetType() == typeof(RopNotifyResponse) || response.GetType() == typeof(RopPendingResponse), "The ROP response type should be RopNotifyResponse or RopPendingResponse.");
                    if (response is RopNotifyResponse)
                    {
                        isServerCreateSubscription = true;
                    }
                }

                Site.Assert.IsFalse(isServerCreateSubscription, "The server can't send notify response when reset table.");
                #endregion

                #region Create table view by QueryRows
                this.SetColumns(contentTableHandle1, tags);

                // Retrieves rows from content table to get the data of 2 rows
                this.QueryRows(contentTableHandle1, 2);
                #endregion

                #region Trigger TableRowAdded event again and get notification
                this.TriggerTableRowModifiedEvent();

                // Create table view by QueryRows after ResetTable, and trigger table event again the server should send notification response.
                rsp = this.CNOTIFAdapter.GetNotification(true);
                Site.Assert.IsTrue(rsp.Count > 0, "The response should contain notification message.");
                foreach (IDeserializable response in rsp)
                {
                    Site.Assert.IsTrue(response.GetType() == typeof(RopNotifyResponse) || response.GetType() == typeof(RopPendingResponse), "The ROP response type should be RopNotifyResponse or RopPendingResponse.");
                    if (response is RopNotifyResponse)
                    {
                        isServerCreateSubscription = true;
                    }
                }

                Site.Assert.IsTrue(isServerCreateSubscription, "After resetting table, the server should send notify response when a new table view is created by RopQueryRows.");
                #endregion

                #region Verify notification response after reset Table and create table view by QueryRows

                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCNTOIF_R281");

                // Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R281
                // Since the server return the notification after a table view is created by RopQueryRows, this requirement can be verified directly.
                Site.CaptureRequirement(
                    281,
                    @"[In Appendix A: Product Behavior] The implementation does stop sending notifications if the RopResetTable ROP ([MS-OXCROPS] section 2.2.5.15) is received, until a new table view is created using one of the following ROPs: RopQueryRows. (Exchange 2010 and above follow this behavior.)");
                #endregion
            }
        }
S02_SubscribeAndReceiveNotifications