public void MSOXCNOTIF_S02_TC04_VerifyTableRowModifyEventAndCreateTableViewByTableSeekRow()
{
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 SeekRow
// The properties need to be set
PropertyTag[] tags = new PropertyTag[]
{
PropertyTags.All[PropertyNames.PidTagInstID],
PropertyTags.All[PropertyNames.PidTagImportance],
PropertyTags.All[PropertyNames.PidTagInstanceNum],
PropertyTags.All[PropertyNames.PidTagFolderId],
PropertyTags.All[PropertyNames.PidTagMessageClass]
};
this.SetColumns(contentTableHandle1, tags);
// Seek the table from the position 1
this.SeekRow(contentTableHandle1, 1);
#endregion
#region Trigger tableRowModified event and get notification
this.TriggerTableRowModifiedEvent();
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 tableRowModified 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.TableRowModified, notifyResponse.NotificationData.TableEvent, "The table event type for the RopNotify response should be TableRowModified.");
this.VerifyTableModifyNotificationFlag(notifyResponse);
this.VerifyTableRowModifiedNotificationElements(notifyResponse);
PropertyTag[] tags1 = new PropertyTag[] { PropertyTags.All[PropertyNames.PidTagFolderId], PropertyTags.All[PropertyNames.PidTagInstanceNum], PropertyTags.All[PropertyNames.PidTagMid] };
// Open Inbox folder and get content table of the Inbox folder
this.OpenFolder(this.InboxFolderId, out inboxTableHandle);
this.GetContentsTable(inboxTableHandle, out contentTableHandle2, false);
// Create table view by QueryRows
this.SetColumns(contentTableHandle2, tags1);
// Retrieves rows from content table to get the data of 30 rows
RopQueryRowsResponse queryResponse = this.QueryRows(contentTableHandle2, 30);
ulong insertAfterTableRowIDFromTable = 0, insertAfterTableRowFolderIDFromTable = 0;
// Get the old value of the Message ID structure of the item triggering the notification.
for (int i = 0; i < queryResponse.RowData.PropertyRows.Count; i++)
{
if (BitConverter.ToUInt64(queryResponse.RowData.PropertyRows[i].PropertyValues[2].Value, 0) == this.TriggerMessageId)
{
// If the message that triggers the notification is in the first row, the insert row should be 0.
// Otherwise, the inserted row is the previous row the message which trigger the notification.
if (i == 0)
{
insertAfterTableRowIDFromTable = 0;
insertAfterTableRowFolderIDFromTable = 0;
}
else
{
insertAfterTableRowIDFromTable = BitConverter.ToUInt64(queryResponse.RowData.PropertyRows[i - 1].PropertyValues[2].Value, 0);
insertAfterTableRowFolderIDFromTable = BitConverter.ToUInt64(queryResponse.RowData.PropertyRows[i - 1].PropertyValues[0].Value, 0);
}
}
}
// Add the debug information
this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCNOTIF_R157");
// Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R157
this.Site.CaptureRequirementIfAreEqual<ulong?>(
insertAfterTableRowIDFromTable,
notifyResponse.NotificationData.InsertAfterTableRowID,
157,
@"[In NotificationData Structure] InsertAfterTableRowID: The old value of the Message ID structure of the item triggering the notification.");
// Add the debug information
this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCNOTIF_R153");
// Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R153
this.Site.CaptureRequirementIfAreEqual<ulong?>(
insertAfterTableRowFolderIDFromTable,
notifyResponse.NotificationData.InsertAfterTableRowFolderID,
153,
@"[In NotificationData Structure] InsertAfterTableRowFolderID: The old value of the Folder ID structure of the item triggering the notification.");
// Add the debug information
this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCNOTIF_R161003");
// Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R161003
this.Site.CaptureRequirementIfIsTrue(
notifyResponse.NotificationData.InsertAfterTableRowInstance != null && (notifyResponse.NotificationData.NotificationFlags & 0x8000) == 0x8000 && notifyResponse.NotificationData.TableEventType == 0x0005,
161003,
@"[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 0x0005.");
// Add the debug information
this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCNOTIF_R263: 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_R263
bool isVerifiedR263 = notifyResponse.NotificationData.TableRowFolderID != null && notifyResponse.NotificationData.TableRowMessageID != null;
this.Site.CaptureRequirementIfIsTrue(
isVerifiedR263,
263,
@"[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 TableRowModified 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(isVerifiedR263);
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_R131");
// Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R131
this.Site.CaptureRequirementIfAreEqual<int>(
0x0005,
(int)notifyResponse.NotificationData.TableEventType,
131,
@"[In NotificationData Structure] [TableEventType value] 0x0005: The notification is for TableRowModified events.");
// Add the debug information
this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCNOTIF_R25");
// Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R25
// The client can receive TableRowModified notification indicates that an existing row has been modified in the table.
this.Site.CaptureRequirementIfAreEqual<int>(
0x0005,
(int)notifyResponse.NotificationData.TableEventType,
25,
@"[In TableModified Event Types] TableRowModified: An existing row has been modified in the table.");
// Only Exchange 2010 and above require a table view, this server version restrict is the same with MS-OXCNTOIF_R245.
if (Common.IsRequirementEnabled(245, this.Site))
{
// 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(
253,
@"[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: RopSeekRow ([MS-OXCROPS] section 2.2.5.8)");
this.VerifyTableViewCreated();
}
}
}
#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(283, 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 resetting table.");
#endregion
#region Create table view by SeekRow
this.SetColumns(contentTableHandle1, tags);
// Seek the table from the position 1
this.SeekRow(contentTableHandle1, 1);
#endregion
#region Trigger TableRowAdded event again and get notification
this.TriggerTableRowAddedEvent();
// Create table view by SeekRow 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 RopSeekRow.");
#endregion
#region Verify notification response after reset Table and create table view by SeekRow
this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCNTOIF_R283");
// Verify MS-OXCNOTIF requirement: MS-OXCNOTIF_R283
// Since the server return the notification after a table view is created by RopSeekRow, this requirement can be verified directly.
Site.CaptureRequirement(
283,
@"[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: RopSeekRow. (Exchange 2010 and above follow this behavior.)");
#endregion
}
}