public void WindowsIdMappingTest()
        {
            Utils.CheckTimeDrift(Fixture, Output);

            // Disconnect from the PISERVER
            Output.WriteLine($"Disconnect from PI Server [{Fixture.PIServer}].");
            Fixture.PIServer.Disconnect();

            AFTime startTime   = AFTime.Now.ToPIPrecision();
            string startTimePI = PIDAUtilities.ToPiTimeString(startTime.LocalTime);

            // Connect again to check for the logs for identity used to get into PISERVER
            Output.WriteLine($"Reconnect to PI Server [{Fixture.PIServer}].");
            Fixture.PIServer.Connect();

            // window of time to check for logged messages
            AFTime endTime       = startTime + TimeSpan.FromMinutes(5);
            string endTimePI     = PIDAUtilities.ToPiTimeString(endTime.LocalTime);
            int    expectedMsgID = 7082;

            Output.WriteLine($"Check if user is logged in through Windows Login.");
            AssertEventually.True(() =>
            {
                // Checks for windows login five times
                return(PIDAUtilities.FindMessagesInLog(Fixture, startTimePI, endTimePI, expectedMsgID, "*Method: Windows Login*"));
            },
                                  TimeSpan.FromSeconds(15),
                                  TimeSpan.FromSeconds(3),
                                  "Windows login not found.");
        }
        public void PIPointSearchTest()
        {
            PIServer piServer = PIFixture.PIServer;
            int      numberOfPointsToCreate = 10;
            var      pointPrefix            = "PIPointSearchTest_Point";

            try
            {
                // Create PI Points
                Output.WriteLine($"Creating PI Points with prefix [{pointPrefix}].");
                var points = PIFixture.CreatePIPoints($"{pointPrefix}#", numberOfPointsToCreate);

                // Assign range of values to defined tags
                for (int i = 0; i < points.Count(); i++)
                {
                    points.ElementAt(i).UpdateValue(new AFValue(Math.Pow(-1, i + 1), null), 0);

                    // Set the Step attribute of half of the PI Points to true and half to false
                    points.ElementAt(i).SetAttribute(PICommonPointAttributes.Step, Convert.ToBoolean(1 * ((i + 1) % 2)));
                    points.ElementAt(i).SaveAttributes();
                }

                // Search PI Points with queries
                var searchQuery = $"Name:'{pointPrefix}*' value:>0";
                Output.WriteLine($"Searching for PI Points with query [{searchQuery}].");
                var parsedQuery       = PIPointQuery.ParseQuery(piServer, searchQuery);
                var searchPointsCount = PIPoint.FindPIPoints(piServer, parsedQuery).Count();
                AssertEventually.True(
                    () => PIPoint.FindPIPoints(piServer, parsedQuery).Count() == (numberOfPointsToCreate / 2),
                    TimeSpan.FromSeconds(10),
                    TimeSpan.FromSeconds(0.5),
                    $"The PI Points count do not match. Expected: {numberOfPointsToCreate / 2}, Actual: {searchPointsCount}.");

                searchQuery = $"Name:'{pointPrefix}*'";
                Output.WriteLine($"Searching for PI Points with query [{searchQuery}].");
                parsedQuery       = PIPointQuery.ParseQuery(piServer, searchQuery);
                searchPointsCount = PIPoint.FindPIPoints(piServer, parsedQuery).Count();
                AssertEventually.True(
                    () => PIPoint.FindPIPoints(piServer, parsedQuery).Count() == numberOfPointsToCreate,
                    TimeSpan.FromSeconds(10),
                    TimeSpan.FromSeconds(0.5),
                    $"The PI Points count do not match. Expected: {numberOfPointsToCreate}, Actual: {searchPointsCount}.");

                searchQuery = $"Name:'{pointPrefix}*' step:=0";
                Output.WriteLine($"Searching for PI Points with query [{searchQuery}].");
                parsedQuery       = PIPointQuery.ParseQuery(piServer, searchQuery);
                searchPointsCount = PIPoint.FindPIPoints(piServer, parsedQuery).Count();
                AssertEventually.True(
                    () => PIPoint.FindPIPoints(piServer, parsedQuery).Count() == (numberOfPointsToCreate / 2),
                    TimeSpan.FromSeconds(10),
                    TimeSpan.FromSeconds(0.5),
                    $"The PI Points count do not match. Expected: {numberOfPointsToCreate / 2}, Actual: {searchPointsCount}.");
            }
            finally
            {
                PIFixture.DeletePIPoints("PIPointSearchTest_Point*", Output);
            }
        }
Пример #3
0
        public void StreamUpdatesTest()
        {
            var testStart = DateTime.UtcNow;

            // Get Data Archive object from PI Web API to extract its WebId
            var dataArchiveUrl = $"{Fixture.HomePageUrl}/dataservers?path=\\\\PIServers[{Settings.PIDataArchive}]";

            Output.WriteLine($"Get Data Archive data through Web API using Url [{dataArchiveUrl}].");
            var dataArchiveData = JObject.Parse(Fixture.Client.DownloadString(dataArchiveUrl));

            // Verifies test PI Point is found
            var piPointUrl = $"{Fixture.HomePageUrl}/dataservers/{(string)dataArchiveData["WebId"]}/points?nameFilter={PIPointName}";

            Output.WriteLine($"Get PI Point data for [{PIPointName}] through Web API using Url [{piPointUrl}].");
            var piPointData = JObject.Parse(Fixture.Client.DownloadString(piPointUrl));

            Assert.True(piPointData["Items"].Count() > 0, $"Could not find test PI Point [{PIPointName}].");
            var webId = piPointData["Items"][0]["WebId"].ToString();

            var streamUrl    = $"{Fixture.HomePageUrl}/streams/{webId}";
            var registerUrl  = $"{streamUrl}/updates";
            var response     = Fixture.Client.UploadString(registerUrl, "POST", string.Empty);
            var registerData = JObject.Parse(response);
            var marker       = (string)registerData["LatestMarker"];

            // Wait for value to update from analysis
            var updatesUrl = $"{Fixture.HomePageUrl}/streams/updates/{marker}";

            // Request stream updates using marker every 5 seconds until new events received and verify new value found in updates
            Output.WriteLine($"Get stream updates through Web API using Url [{updatesUrl}].");
            var waitTimeInSeconds     = 60;
            var pollIntervalInSeconds = 5;

            AssertEventually.True(
                () => JObject.Parse(Fixture.Client.DownloadString(updatesUrl))["Events"].ToObject <List <JObject> >().Count() > 0,
                TimeSpan.FromSeconds(waitTimeInSeconds),
                TimeSpan.FromSeconds(pollIntervalInSeconds),
                "No new events received via stream updates.");

            Output.WriteLine($"Verify new value in stream updates.");
            AssertEventually.True(
                () =>
            {
                var updateData   = JObject.Parse(Fixture.Client.DownloadString(updatesUrl));
                var updateEvents = updateData["Events"].ToObject <List <JObject> >();

                var updateEvent = updateEvents.Last();
                var timeStamp   = (DateTime)updateEvent["Timestamp"];
                return(timeStamp > testStart);
            },
                TimeSpan.FromSeconds(waitTimeInSeconds),
                TimeSpan.FromSeconds(pollIntervalInSeconds),
                $"Test failed to retrieve a stream updates event with a timestamp after test start time [{testStart}] within {waitTimeInSeconds} seconds. " +
                $"This may indicate that the data ingress for {PIPointName} to PI Data Archive was delayed, or a longer CalculationWaitTimeInSeconds " +
                $"has been set in Analysis Service Configuration.");
        }
        public void TimeSeriesUpdatesTest()
        {
            // Construct a unique PI Point name
            string pointNameFormat = $"TimeSeriesUpdateTestPoint{AFTime.Now}";

            bool signupCompleted = false;

            using (var myDataPipe = new PIDataPipe(AFDataPipeType.TimeSeries))
            {
                Output.WriteLine($"Create a PI Point on [{Settings.PIDataArchive}] with compression off.");
                var points = Fixture.CreatePIPoints(pointNameFormat, 1, true);

                try
                {
                    Output.WriteLine($"Sign up for time-series updates on PI Point [{pointNameFormat}].");
                    myDataPipe.AddSignups(points.ToList());
                    signupCompleted = true;

                    var startTime  = AFTime.Now.ToPIPrecision() + TimeSpan.FromDays(-1);
                    int eventCount = 1000;
                    int totalCount = 0;

                    // Send events to each PI Point, the event's value is calculated from the timestamp
                    Output.WriteLine($"Write {eventCount} events to the new PI Point.");
                    Fixture.SendTimeBasedPIEvents(startTime, eventCount, points.ToList());

                    // Checks if Update Events are retrieved a few times
                    Output.WriteLine($"Get the update events.");

                    var eventsRetrieved = new AFListResults <PIPoint, AFDataPipeEvent>();
                    AssertEventually.True(() =>
                    {
                        eventsRetrieved = myDataPipe.GetUpdateEvents(eventCount);
                        totalCount     += eventsRetrieved.Count();
                        return(totalCount == eventCount);
                    },
                                          TimeSpan.FromSeconds(60),
                                          TimeSpan.FromSeconds(1),
                                          $"Failed to retrieve {eventCount} update events, retrieved {totalCount} instead.");
                    Output.WriteLine("Retrieved update events successfully.");
                }
                finally
                {
                    if (signupCompleted)
                    {
                        myDataPipe.RemoveSignups(points.ToList());
                    }

                    Output.WriteLine("Delete all newly created PI Points.");
                    Fixture.DeletePIPoints(pointNameFormat, Output);
                }
            }
        }
Пример #5
0
        public void ChannelsTest()
        {
            var testStart = DateTime.UtcNow;

            // Get Data Archive object from PI Web API to extract its WebId
            var dataArchiveUrl = $"{Fixture.HomePageUrl}/dataservers?path=\\PIServers[{Settings.PIDataArchive}]";

            Output.WriteLine($"Get Data Archive data through Web API using Url [{dataArchiveUrl}].");
            var dataArchiveData = JObject.Parse(Fixture.Client.DownloadString(dataArchiveUrl));

            // Verifies test PI Point is found
            var piPointUrl = $"{Fixture.HomePageUrl}/dataservers/{(string)dataArchiveData["WebId"]}/points?nameFilter={PIPointName}";

            Output.WriteLine($"Get PI Point data for [{PIPointName}] through Web API using Url [{piPointUrl}].");
            var piPointData = JObject.Parse(Fixture.Client.DownloadString(piPointUrl));

            Assert.True(piPointData["Items"].Count() > 0, $"Could not find test PI Point [{PIPointName}].");
            var webId = piPointData["Items"][0]["WebId"].ToString();

            Output.WriteLine($"Open channel to a stream for PI Point data for [{PIPointName}].");
            var waitTimeInSeconds     = 60;
            var pollIntervalInSeconds = 5;

            AssertEventually.True(
                () =>
            {
                using (var cancellationSource = new CancellationTokenSource())
                {
                    var runTask        = ReadChannelData(webId, cancellationSource.Token);
                    var timeOutSeconds = waitTimeInSeconds;
                    var taskCompleted  = runTask.Wait(TimeSpan.FromSeconds(timeOutSeconds));
                    Assert.True(taskCompleted, $"The channel for [{PIPointName}] did not return data from its stream in the allotted time frame ({timeOutSeconds} seconds).");
                }

                Assert.True(_channelMessage != null, $"The channel for [{PIPointName}] did not return data from its stream.");
                var updateEvent = JObject.Parse(_channelMessage);
                var timeStamp   = (DateTime)updateEvent["Items"][0]["Items"][0]["Timestamp"];

                return(timeStamp > testStart);
            },
                TimeSpan.FromSeconds(waitTimeInSeconds),
                TimeSpan.FromSeconds(pollIntervalInSeconds),
                $"Test failed to retrieve a channel event with a timestamp after test start time [{testStart}] within {waitTimeInSeconds} seconds. " +
                $"This may indicate that the data ingress for {PIPointName} to PI Data Archive was delayed, or a longer CalculationWaitTimeInSeconds " +
                $"has been set in Analysis Service Configuration.");
        }
        public void PIPointsTest()
        {
            PIServer piServer    = PIFixture.PIServer;
            int      count       = 10;
            var      pointPrefix = "PIPointsTest_Point";

            try
            {
                // Create PI Point and verify
                Output.WriteLine($"Creating PI Points with prefix [{pointPrefix}] with default attributes and verifying.");
                var points         = PIFixture.CreatePIPoints($"{pointPrefix}#", count);
                var returnedPoints = PIPoint.FindPIPoints(piServer, $"{pointPrefix}*");
                Assert.True(returnedPoints.Count() == count, $"Expected to find {count} PI Points on Data Archive [{piServer}], actually found {returnedPoints.Count()}.");

                var timestamp = new AFTime("*-10m");

                // Set Value of PI Points
                Output.WriteLine("Updating PI Points with new values.");
                for (int i = 0; i < returnedPoints.Count(); i++)
                {
                    returnedPoints.ElementAt(i).UpdateValue(new AFValue(i, timestamp), AFUpdateOption.NoReplace);
                }

                // Check for updated values
                Output.WriteLine("Checking PI Points were updated with new values.");
                for (int i = 0; i < count; i++)
                {
                    AssertEventually.Equals(returnedPoints.ElementAt(i).CurrentValue(), new AFValue(Convert.ToSingle(i), timestamp.ToPIPrecision()));
                }

                // Delete PI Points and verify
                Output.WriteLine("Deleting PI Points that were created and verifying.");
                PIFixture.DeletePIPoints($"{pointPrefix}*", Output);
                returnedPoints = PIPoint.FindPIPoints(piServer, $"{pointPrefix}*");
                Assert.True(returnedPoints.Count() == 0,
                            $"Expected to find no PI Points with prefix [{pointPrefix}], but {returnedPoints.Count()} were found.");
            }
            finally
            {
                PIFixture.DeletePIPoints($"{pointPrefix}*", Output);
            }
        }
        public void WindowsIdMappingTest()
        {
            Utils.CheckTimeDrift(Fixture, Output);

            // Disconnect from the PISERVER
            Output.WriteLine($"Disconnect from PI Server [{Fixture.PIServer}].");
            Fixture.PIServer.Disconnect();

            AFTime startTime   = AFTime.Now.ToPIPrecision();
            string startTimePI = PIDAUtilities.ToPiTimeString(startTime.LocalTime);

            // Connect again to check for the logs for identity used to get into PISERVER
            Output.WriteLine($"Reconnect to PI Server [{Fixture.PIServer}].");
            Fixture.PIServer.Connect();

            // window of time to check for logged messages
            AFTime endTime       = startTime + TimeSpan.FromMinutes(5);
            string endTimePI     = PIDAUtilities.ToPiTimeString(endTime.LocalTime);
            int    expectedMsgID = 7082;

            Output.WriteLine($"Check if {PIFixture.RequiredPIIdentity} is one of the user identities.");
            AssertEventually.True(() =>
            {
                // The test server is expected to have a mapping for the user running the tests mapped to piadmins.
                // check piadmins identity is in the list
                // Then we check if the Windows Login method is used
                IList <PIIdentity> myCurrentList = Fixture.PIServer.CurrentUserIdentities;
                myCurrentList.Single(x => x.Name.Equals(PIFixture.RequiredPIIdentity, StringComparison.OrdinalIgnoreCase));

                // Checks for windows login five times
                return(PIDAUtilities.FindMessagesInLog(Fixture, startTimePI, endTimePI, expectedMsgID, "*Method: Windows Login*"));
            },
                                  TimeSpan.FromSeconds(15),
                                  TimeSpan.FromSeconds(3),
                                  "Windows login not found.");
        }
        public void CheckPIPointWritePermissionTest()
        {
            using (var piFixture = new PIFixture())
            {
                // Find the target a PI Point
                string manualInputPoint = @"OSIsoftTests.Region 1.Manual Input";
                Output.WriteLine($"Search for PI Point [{manualInputPoint}].");
                var point = PIPoint.FindPIPoint(piFixture.PIServer, manualInputPoint);

                // Prepare the event to be written
                var eventToWrite = new AFValue((float)Math.PI, (AFTime.Now + TimeSpan.FromSeconds(1)).ToPIPrecision());

                // Send the event to be written
                Output.WriteLine($"Write an event to PI Point [{manualInputPoint}].");
                point.UpdateValue(eventToWrite, AFUpdateOption.InsertNoCompression);

                // Read the current value to verify that the event was written successfully
                Output.WriteLine($"Verify the event has been sent to PI Point [{manualInputPoint}].");
                AssertEventually.True(
                    () => eventToWrite.Equals(point.CurrentValue()),
                    $"Failed to send data to PI Point [{manualInputPoint}] on {piFixture.PIServer.Name}.  Please check if the running user has write access to PI Data Archive.  " +
                    $"If buffering is configured, make sure PI Buffer Subsystem connects to PI Data Archive with appropriate PI mappings.");
            }
        }
        public void NotificationRuleSendEmailAnnotationTest()
        {
            AFDatabase db                   = AFFixture.AFDatabase;
            var        elementName          = $"{NotificationsFixture.TestPrefix}_{NotificationsFixture.TestInfix}_{nameof(NotificationRuleSendEmailAnnotationTest)}";
            var        notificationRuleName = $"{NotificationsFixture.TestPrefix}_{NotificationsFixture.TestInfix}_NotificationRule1";
            var        eventFrameName       = $"{NotificationsFixture.TestPrefix}_{NotificationsFixture.TestInfix}_EventFrame1";

            AFFixture.RemoveElementIfExists(elementName, Output);
            Guid?eventFrameId = null;
            AFNotificationContactTemplate emailEndpoint = null;

            try
            {
                emailEndpoint = CreateEmailEndpoint(nameof(NotificationRuleSendEmailAnnotationTest));
                Output.WriteLine($"Create email notification contact template [{emailEndpoint.Name}].");
                PISystem.CheckIn();

                Output.WriteLine($"Create element [{elementName}] with notification rule [{notificationRuleName}]");
                var element          = db.Elements.Add(elementName);
                var notificationRule = element.NotificationRules.Add(notificationRuleName);
                notificationRule.Criteria = $"Name:{NotificationsFixture.TestPrefix}*";
                var format = notificationRule.DeliveryFormats.Add("testFormat", EmailPlugIn);
                NotificationsFixture.SetFormatProperties(format.Properties, nameof(NotificationRuleSendEmailAnnotationTest));

                var subscriber = notificationRule.Subscribers.Add(emailEndpoint);
                subscriber.DeliveryFormat = format;

                notificationRule.SetStatus(AFStatus.Enabled);
                db.CheckIn();

                Output.WriteLine("Waiting for notification to startup.");
                Thread.Sleep(TimeSpan.FromSeconds(10));

                var eventFrame = new AFEventFrame(db, eventFrameName)
                {
                    PrimaryReferencedElement = element,
                };

                eventFrame.SetStartTime(AFTime.Now);
                eventFrame.CheckIn();
                eventFrameId = eventFrame.ID;
                Output.WriteLine($"Created event frame [{eventFrameName}].");

                // Verify annotations are gotten correctly
                var annotations = eventFrame.GetAnnotations();
                if (annotations.Count == 0)
                {
                    AssertEventually.True(
                        () => eventFrame.GetAnnotations().Count != 0,
                        TimeSpan.FromSeconds(60),
                        TimeSpan.FromSeconds(5),
                        "Did not find any annotations.");
                    annotations = eventFrame.GetAnnotations();
                }

                Output.WriteLine("Verify the notification is sent for the event frame and the annotation is set properly.");
                Assert.True(annotations.Count == 1, $"Expected to get only one annotation, but got {annotations.Count}.");
                Assert.True(annotations[0].Owner.ID == eventFrameId, "The owner of the annotation is not set properly.");
                Assert.True(annotations[0].Name == NotificationsFixture.AnnotationName, "The name of the annotation is not set properly.");
                Assert.False(string.IsNullOrWhiteSpace(annotations[0].Description), "The description of the annotation is not set properly.");
                Assert.True((string)annotations[0].Value == string.Format(CultureInfo.InvariantCulture, NotificationsFixture.SentAnnotation, 1),
                            "The value of the annotation is not set properly.");

                Output.WriteLine("Verify the content of the annotation is set properly.");
                Assert.False(string.IsNullOrWhiteSpace(annotations[0].Description), "The description of the annotation is not set properly.");
                var description = NotificationsFixture.DeserializeAnnotationDescription(annotations[0].Description);
                var subscribers = description.Subscribers;
                Assert.True(description.Notification == notificationRuleName, "The notification rule name is not set properly.");
                Assert.True(subscribers.Count == 1, $"Expected to get only one subscriber, but got {description.Subscribers.Count}.");
                Assert.True(subscribers[0].Name == emailEndpoint.Name, "The name of the subscriber is not set properly.");
                Assert.True(subscribers[0].Configuration == Settings.PINotificationsRecipientEmailAddress, "The email address of the subscriber is not set properly.");
                Assert.True(subscribers[0].Type == "Email", "The type of the subscriber is not set properly.");
            }
            finally
            {
                AFFixture.RemoveElementIfExists(elementName, Output);
                if (eventFrameId != null)
                {
                    AFFixture.RemoveEventFrameIfExists(eventFrameId.GetValueOrDefault(), Output);
                }

                if (emailEndpoint != null)
                {
                    PISystem.NotificationContactTemplates.Remove(emailEndpoint.ID);
                    PISystem.CheckIn();
                }
            }
        }
        public void NotificationRuleSendToEscalationContactTest()
        {
            AFDatabase db                   = AFFixture.AFDatabase;
            var        elementName          = $"{NotificationsFixture.TestPrefix}_{NotificationsFixture.TestInfix}_{nameof(NotificationRuleSendToEscalationContactTest)}";
            var        notificationRuleName = $"{NotificationsFixture.TestPrefix}_{NotificationsFixture.TestInfix}_NotificationRule1";
            var        escalationNotificationContactTemplateName = $"{NotificationsFixture.TestPrefix}_{NotificationsFixture.TestInfix}_Escalation1";
            var        eventFrameName = $"{NotificationsFixture.TestPrefix}_{NotificationsFixture.TestInfix}_EventFrame1";
            var        emailContactsCountInEscalation = 2;
            var        escalationPeriod = TimeSpan.FromSeconds(20);

            AFFixture.RemoveElementIfExists(elementName, Output);
            Guid?eventFrameId   = null;
            var  emailEndpoints = new List <AFNotificationContactTemplate>();
            AFNotificationContactTemplate escalation = null;

            try
            {
                Output.WriteLine($"Created group notification contact template [{escalationNotificationContactTemplateName}]" +
                                 $" with [{emailContactsCountInEscalation}] email notification contact added.");
                escalation = new AFNotificationContactTemplate(PISystem, escalationNotificationContactTemplateName)
                {
                    ContactType       = AFNotificationContactType.Escalation,
                    EscalationTimeout = escalationPeriod,
                };
                escalation.CheckIn();

                for (var i = 0; i < emailContactsCountInEscalation; i++)
                {
                    var emailEndpoint = CreateEmailEndpoint($"{nameof(NotificationRuleSendToEscalationContactTest)}_{i}");
                    escalation.NotificationContactTemplates.Add(emailEndpoint);
                    emailEndpoints.Add(emailEndpoint);
                }

                PISystem.CheckIn();

                Output.WriteLine($"Created element [{elementName}] with notification rule [{notificationRuleName}].");
                var element          = db.Elements.Add(elementName);
                var notificationRule = element.NotificationRules.Add(notificationRuleName);
                notificationRule.Criteria = $"Name:{NotificationsFixture.TestPrefix}*";
                var subscriber = notificationRule.Subscribers.Add(escalation);
                notificationRule.SetStatus(AFStatus.Enabled);
                db.CheckIn();

                Output.WriteLine("Waiting for notification to startup.");
                Thread.Sleep(TimeSpan.FromSeconds(10));

                var eventFrame = new AFEventFrame(db, eventFrameName)
                {
                    PrimaryReferencedElement = element,
                };

                Output.WriteLine($"Create event frame [{eventFrameName}].");
                eventFrame.SetStartTime(AFTime.Now);
                eventFrame.CheckIn();
                eventFrameId = eventFrame.ID;

                Output.WriteLine("Waiting for escalation period.");
                Thread.Sleep(TimeSpan.FromSeconds(30));

                // Verify annotations are gotten correctly
                var annotations = eventFrame.GetAnnotations();
                if (annotations.Count == 0)
                {
                    AssertEventually.True(
                        () => eventFrame.GetAnnotations().Count != 0,
                        TimeSpan.FromSeconds(60),
                        TimeSpan.FromSeconds(5),
                        "Did not find any annotations.");
                    annotations = eventFrame.GetAnnotations();
                }

                Output.WriteLine("Verify the notification is sent for the event frame and the annotation is set properly.");
                Assert.True(annotations.Count == emailContactsCountInEscalation, $"Expected to get [{emailContactsCountInEscalation}] annotations, but got [{annotations.Count}].");
                for (var i = 0; i < emailContactsCountInEscalation; i++)
                {
                    Assert.True(annotations[i].Name == NotificationsFixture.AnnotationName, "The name of the annotation is not set properly.");

                    Assert.False(string.IsNullOrWhiteSpace(annotations[i].Description), "The description of the annotation is not set properly.");
                    var description = NotificationsFixture.DeserializeAnnotationDescription(annotations[i].Description);
                    var subscribers = description.Subscribers;
                    Assert.True(description.Notification == notificationRuleName, "The notification rule name is not set properly.");
                    Assert.True(subscribers.Count == 1, $"Expected to get only one subscriber, but got {description.Subscribers.Count}.");
                    Assert.True(subscribers[0].Name == emailEndpoints[i].Name, $"The name of the [{i}] subscriber is not set properly.");
                    Assert.True(subscribers[0].Configuration == Settings.PINotificationsRecipientEmailAddress, $"The configuration of the [{i}] subscriber is not displayed in the annotation.");
                    Assert.True(subscribers[0].Type == "Email", $"The type of the [{i}] subscriber is not set properly.");

                    if (i == 0)
                    {
                        Assert.True((string)annotations[i].Value == string.Format(CultureInfo.InvariantCulture, NotificationsFixture.SentAnnotation, 1),
                                    "The value of the annotation is not set properly.");
                    }
                    else
                    {
                        Assert.True((string)annotations[i].Value == string.Format(CultureInfo.InvariantCulture, NotificationsFixture.EscalatedAnnotation, 1),
                                    "The value of the annotation is not set properly.");
                    }
                }

                for (var i = emailContactsCountInEscalation - 1; i > 0; i--)
                {
                    Assert.True(annotations[i].CreationDate - annotations[i - 1].CreationDate >= escalationPeriod, $"The escalation period is not performed properly.");
                }
            }
            finally
            {
                AFFixture.RemoveElementIfExists(elementName, Output);
                if (eventFrameId != null)
                {
                    AFFixture.RemoveEventFrameIfExists(eventFrameId.GetValueOrDefault(), Output);
                }

                if (escalation != null)
                {
                    PISystem.NotificationContactTemplates.Remove(escalation.ID);
                }

                foreach (var emailEndpoint in emailEndpoints)
                {
                    PISystem.NotificationContactTemplates.Remove(emailEndpoint.ID);
                }

                PISystem.CheckIn();
            }
        }
        public void PIDataPipeTimeSeriesTest(PIPointType piPointType, object[] eventValues)
        {
            Contract.Requires(eventValues != null);

            const string PointName = "PIDataPipeTests_PIPoint";

            AFDatabase db         = AFFixture.AFDatabase;
            PIServer   piServer   = PIFixture.PIServer;
            var        piDataPipe = new PIDataPipe(AFDataPipeType.TimeSeries);

            var piPointList = new PIPointList();
            var now         = AFTime.NowInWholeSeconds;

            try
            {
                Output.WriteLine("Create the Future PI Points with Zero Compression and specified PI Point type.");
                PIFixture.DeletePIPoints(PointName + "*", Output);
                var testPIPoints = PIFixture.CreatePIPoints(PointName + "###", eventValues.Length, new Dictionary <string, object>
                {
                    { PICommonPointAttributes.PointType, piPointType },
                    { PICommonPointAttributes.ExceptionDeviation, 0 },
                    { PICommonPointAttributes.ExceptionMaximum, 0 },
                    { PICommonPointAttributes.Compressing, 0 },
                    { PICommonPointAttributes.DigitalSetName, "Phases" },
                    { PICommonPointAttributes.Future, true },
                });
                Assert.True(testPIPoints.Count() == eventValues.Length, $"Unable to create all the test PI Points.");
                piPointList.AddRange(testPIPoints);

                // Add the PI Point as sign up to the PIDataPipe.
                Output.WriteLine($"Sign up all PI Points with PIDataPipe.");
                var afErrors           = piDataPipe.AddSignups(piPointList);
                var prefixErrorMessage = "Adding sign ups to the PIDataPipe was unsuccessful.";
                Assert.True(afErrors == null,
                            userMessage: afErrors?.Errors.Aggregate(prefixErrorMessage, (msg, error) => msg += $" PI Point: [{error.Key.Name}] Error: [{error.Value.Message}] "));

                // Write one data value to each PI Point.
                var expectedAFValues = new AFValues();
                for (int i = 0; i < eventValues.Length; i++)
                {
                    AFValue afValue   = null;
                    var     timestamp = now + TimeSpan.FromMinutes(i - eventValues.Length);

                    // Special Handling of Input Data for Digital and Timestamp
                    switch (piPointType)
                    {
                    case PIPointType.Digital:
                        afValue = new AFValue(new AFEnumerationValue("Phases", (int)eventValues[i]), timestamp);
                        break;

                    case PIPointType.Timestamp:
                        afValue = new AFValue(new AFTime(eventValues[i], now), timestamp);
                        break;

                    default:
                        afValue = new AFValue(eventValues[i], timestamp);
                        break;
                    }

                    Output.WriteLine($"Writing Value [{eventValues[i]}] with Timestamp [{timestamp}] to PI Point [{piPointList[i].Name}].");
                    piPointList[i].UpdateValue(afValue, AFUpdateOption.InsertNoCompression);

                    // If writing digital states, we need to save the corresponding value for verification.
                    // Since we are using Phases, 0 ~ Phase1, 1 ~ Phase2, etc.
                    if (piPointType == PIPointType.Digital)
                    {
                        int input = (int)eventValues[i];
                        afValue = new AFValue(new AFEnumerationValue($"Phase{input + 1}", input), timestamp);
                    }

                    afValue.PIPoint = piPointList[i];
                    expectedAFValues.Add(afValue);
                }

                // Retry assert to retrieve expected Update Events from the PIDataPipe
                var actualAFValues = new AFValues();
                Output.WriteLine($"Reading Events from the PI DataPipe.");
                AssertEventually.True(() =>
                {
                    var updateEvents = piDataPipe.GetUpdateEvents(eventValues.Length);

                    prefixErrorMessage = "Retrieving Update Events from the PIDataPipe was unsuccessful.";
                    Assert.False(updateEvents.HasErrors,
                                 userMessage: updateEvents.Errors?.Aggregate(prefixErrorMessage, (msg, error) => msg += $" PI Point: [{error.Key.Name}] Error: [{error.Value.Message}] "));

                    actualAFValues.AddRange(updateEvents.Results.Select(update => update.Value));
                    if (actualAFValues.Count >= expectedAFValues.Count)
                    {
                        // Verify that all expected update events are received from the PIDataPipe
                        Assert.True(expectedAFValues.Count == actualAFValues.Count, "PIDataPipe returned more events than expected. " +
                                    $"Expected Count: {expectedAFValues.Count}, Actual Count: {actualAFValues.Count}.");
                        return(true);
                    }

                    return(false);
                },
                                      TimeSpan.FromSeconds(5),
                                      TimeSpan.FromSeconds(0.5),
                                      "Unable to retrieve events within the time frame.");

                // Verify all received events.
                Output.WriteLine($"Verifying all {actualAFValues.Count} events from the PI DataPipe.");
                for (int i = 0; i < actualAFValues.Count; i++)
                {
                    // Special handling of Output events for Timestamp
                    if (piPointType == PIPointType.Timestamp)
                    {
                        actualAFValues[i].Value = new AFTime(actualAFValues[i].Value, now);
                    }

                    AFFixture.CheckAFValue(actualAFValues[i], expectedAFValues[i]);
                    Assert.True(object.Equals(actualAFValues[i].PIPoint, expectedAFValues[i].PIPoint),
                                $"Unexpected PI Point Association. Expected: [{expectedAFValues[i].PIPoint}], Actual: [{actualAFValues[i].PIPoint}].");
                }

                // Remove all sign ups from the PIDataPipe
                Output.WriteLine($"Remove all PI Point sign ups from PIDataPipe.");
                afErrors           = piDataPipe.RemoveSignups(piPointList);
                prefixErrorMessage = "Removing sign ups to the PIDataPipe was unsuccessful.";
                Assert.True(afErrors == null,
                            userMessage: afErrors?.Errors.Aggregate(prefixErrorMessage, (msg, error) => msg += $" PI Point: [{error.Key.Name}] Error: [{error.Value.Message}] "));

                // Write dummy values to the PI Points and confirm PI DataPipe receives none.
                Output.WriteLine($"Write dummy values to the PI Points.");
                for (int i = 0; i < eventValues.Length; i++)
                {
                    piPointList[i].UpdateValue(new AFValue(eventValues[i], now), AFUpdateOption.InsertNoCompression);
                }

                Output.WriteLine($"Verify no events are received by the PIDataPipe.");
                var noEvents = piDataPipe.GetUpdateEvents(eventValues.Length);
                prefixErrorMessage = "Retrieving Update Events from the PIDataPipe was unsuccessful.";
                Assert.False(noEvents.HasErrors,
                             userMessage: noEvents.Errors?.Aggregate(prefixErrorMessage, (msg, error) => msg += $" PI Point: [{error.Key.Name}] Error: [{error.Value.Message}] "));

                Assert.True(noEvents.Count == 0, "PIDataPipe received events even after removing all sign ups.");
            }
            finally
            {
                piDataPipe.RemoveSignups(piPointList);
                piDataPipe.Dispose();
                PIFixture.DeletePIPoints(PointName + "*", Output);
            }
        }
        public void CreatePointSendEventsAndVerify()
        {
            string pointName = $"CreatePointSendEventsAndVerify{AFTime.Now}";

            IDictionary<string, object> attributes = new Dictionary<string, object>()
            {
                { PICommonPointAttributes.Tag, pointName },
                { PICommonPointAttributes.PointType, PIPointType.Int32 },
                { PICommonPointAttributes.Compressing, 0 },
            };

            // Create a PI Point
            Output.WriteLine($"Create PI Point [{pointName}].");
            PIPoint point = Fixture.PIServer.CreatePIPoint(pointName, attributes);

            // Assert that the PI Point creation was successful
            Assert.True(PIPoint.FindPIPoint(Fixture.PIServer, pointName) != null,
                $"Could not find PI Point [{pointName}] on Data Archive [{Fixture.PIServer.Name}].");

            try
            {
                // Prepare the events to be written
                var eventsToWrite = new AFValues();
                var start = AFTime.Now.ToPIPrecision();
                int eventsCount = 10;
                var randomData = new byte[eventsCount];
                using (var random = RandomNumberGenerator.Create())
                {
                    random.GetBytes(randomData);
                }

                for (int i = 0; i < eventsCount; i++)
                {
                    var evnt = new AFValue(Convert.ToInt32(randomData[i]), start + TimeSpan.FromSeconds(i));
                    eventsToWrite.Add(evnt);
                }

                // Send the events to be written
                Output.WriteLine($"Write events to PI Point [{pointName}].");
                point.UpdateValues(eventsToWrite, AFUpdateOption.InsertNoCompression);

                // Read the events to verify that it was written successfully
                var eventsRead = new AFValues();
                Output.WriteLine($"Read events from PI Point [{pointName}].");

                AssertEventually.Equal(
                    eventsToWrite.Count,
                    () => point.RecordedValuesByCount(start, eventsCount, true, AFBoundaryType.Inside, null, false).Count,
                    TimeSpan.FromSeconds(2),
                    TimeSpan.FromSeconds(0.2));

                eventsRead = point.RecordedValuesByCount(start, eventsCount, true, AFBoundaryType.Inside, null, false);

                for (int j = 0; j < eventsCount; j++)
                {
                    Assert.True(eventsToWrite[j].Value.Equals(eventsRead[j].Value),
                        $"Expected the value of the written event {AFFixture.DisplayAFValue(eventsToWrite[j])} " +
                        $"and the read event {AFFixture.DisplayAFValue(eventsRead[j])} to be equal.");
                }
            }
            finally
            {
                // Delete the PI Point to cleanup
                Fixture.DeletePIPoints(pointName, Output);
            }
        }
        public void UpdateEventValuesTest()
        {
            string pointName = $"UpdateEventValuesTest{AFTime.Now}";

            IDictionary<string, object> attributes = new Dictionary<string, object>()
            {
                { PICommonPointAttributes.Tag, pointName },
                { PICommonPointAttributes.PointType, PIPointType.Int32 },
                { PICommonPointAttributes.Compressing, 0 },
            };

            // Create a PI Point
            Output.WriteLine($"Create PI Point [{pointName}].");
            PIPoint point = Fixture.PIServer.CreatePIPoint(pointName, attributes);

            // Assert that the PI Point creation was successful
            Assert.True(PIPoint.FindPIPoint(Fixture.PIServer, pointName) != null,
                $"Could not find PI Point [{pointName}] on Data Archive [{Fixture.PIServer.Name}].");

            try
            {
                // Prepare the events to be written
                var eventsToWrite = new AFValues();
                var start = AFTime.Now.ToPIPrecision();
                int eventsCount = 10;
                var randomData = new byte[eventsCount];
                var valuesToWrite = new List<int>();
                var timeStamps = new List<AFTime>();

                using (var random = RandomNumberGenerator.Create())
                {
                    random.GetBytes(randomData);
                    for (int i = 0; i < eventsCount; i++)
                    {
                        int value = Convert.ToInt32(randomData[i]);
                        var timestamp = start + TimeSpan.FromMinutes(i);
                        var evnt = new AFValue(value, timestamp);
                        eventsToWrite.Add(evnt);
                        valuesToWrite.Add(value);
                        timeStamps.Add(timestamp);
                    }
                }

                // Send the events to be written
                Output.WriteLine($"Write {eventsCount} events to PI Point [{pointName}].");
                point.UpdateValues(eventsToWrite, AFUpdateOption.InsertNoCompression);
                Thread.Sleep(TimeSpan.FromSeconds(1));

                // Read the events to verify that it was written successfully
                var eventsRead = new AFValues();

                Output.WriteLine($"Read events from point [{pointName}].");
                AssertEventually.True(() =>
                {
                    eventsRead = point.RecordedValuesByCount(start, eventsCount, true, AFBoundaryType.Inside, null, false);
                    if (eventsToWrite.Count != eventsRead.Count)
                    {
                        Output.WriteLine($"The read event count {eventsRead.Count} does not match the written event count {eventsToWrite.Count}.");
                        return false;
                    }

                    for (int j = 0; j < eventsCount; j++)
                    {
                        if (!eventsToWrite[j].Value.Equals(eventsRead[j].Value))
                        {
                            Output.WriteLine($"Written event value {AFFixture.DisplayAFValue(eventsToWrite[j])} " +
                                $"did not match read event value {AFFixture.DisplayAFValue(eventsRead[j])}.");
                            return false;
                        }
                    }

                    return true;
                },
                TimeSpan.FromSeconds(30),
                TimeSpan.FromSeconds(5),
                $"The events read back do not match the events written on the PI Data Archive [{Fixture.PIServer.Name}].");

                // Update/edit the values and send again
                var updatedNewValues = new List<int>();
                var eventsUpdated = new AFValues();
                randomData = new byte[eventsCount];

                using (var random = RandomNumberGenerator.Create())
                {
                    random.GetBytes(randomData);
                    for (int i = 0; i < eventsCount; i++)
                    {
                        // Ensure that the updated values are different than the written values.
                        int value = Convert.ToInt32(randomData[i]) + 256;
                        var evnt = new AFValue(value, timeStamps[i]);
                        eventsUpdated.Add(evnt);
                        updatedNewValues.Add(value);
                    }
                }

                // Send the updated events to be written
                Output.WriteLine($"Write updated events to PI Point [{pointName}].");
                point.UpdateValues(eventsUpdated, AFUpdateOption.Replace);

                // Read the events to verify that it was updated successfully
                eventsRead = new AFValues();

                Output.WriteLine($"Read events from PI Point [{pointName}].");
                AssertEventually.True(() =>
                {
                    eventsRead = point.RecordedValuesByCount(start, eventsCount, true, AFBoundaryType.Inside, null, false);
                    if (eventsUpdated.Count != eventsRead.Count)
                    {
                        Output.WriteLine($"The read event count {eventsRead.Count} does not match the updated event count {eventsUpdated.Count}.");
                        return false;
                    }

                    for (int j = 0; j < eventsCount; j++)
                    {
                        if (!eventsUpdated[j].Value.Equals(eventsRead[j].Value))
                        {
                            Output.WriteLine($"Updated event value {AFFixture.DisplayAFValue(eventsUpdated[j])} " +
                                $"did not match read event value {AFFixture.DisplayAFValue(eventsRead[j])}.");
                            return false;
                        }

                        if (eventsToWrite[j].Value.Equals(eventsRead[j].Value))
                        {
                            Output.WriteLine($"Written event value {AFFixture.DisplayAFValue(eventsToWrite[j])} " +
                                $"did match read event value {AFFixture.DisplayAFValue(eventsRead[j])}. The values should not be equal.");
                            return false;
                        }
                    }

                    return true;
                },
                $"The events read back do not match the events written or updated on the PI Data Archive [{Fixture.PIServer.Name}].");
            }
            finally
            {
                // Delete the PI Point to cleanup
                Fixture.DeletePIPoints(pointName, Output);
            }
        }
        public void DeleteValuesTest()
        {
            string pointName = $"DeleteValuesTest{AFTime.Now}";

            IDictionary<string, object> attributes = new Dictionary<string, object>()
            {
                { PICommonPointAttributes.Tag, pointName },
                { PICommonPointAttributes.PointType, PIPointType.Int32 },
                { PICommonPointAttributes.Compressing, 0 },
            };

            // Create a PI Point
            Output.WriteLine($"Create PI Point [{pointName}].");
            PIPoint point = Fixture.PIServer.CreatePIPoint(pointName, attributes);

            // Assert that the PI Point creation was successful
            Assert.True(PIPoint.FindPIPoint(Fixture.PIServer, pointName) != null,
                $"Could not find PI Point [{pointName}] on Data Archive [{Fixture.PIServer.Name}].");

            try
            {
                // Prepare the events to be written
                var eventsToWrite = new AFValues();
                var start = AFTime.Now.ToPIPrecision();
                int eventsCount = 10;
                var randomData = new byte[eventsCount];

                using (var random = RandomNumberGenerator.Create())
                {
                    random.GetBytes(randomData);
                    for (int i = 0; i < eventsCount; i++)
                    {
                        var evnt = new AFValue(Convert.ToInt32(randomData[i]), start + TimeSpan.FromSeconds(i));
                        eventsToWrite.Add(evnt);
                    }
                }

                // Send the events to be written
                Output.WriteLine($"Write events to PI Point [{pointName}].");
                point.UpdateValues(eventsToWrite, AFUpdateOption.InsertNoCompression);

                // Read the events to verify that the events write was successful
                var eventsRead = new AFValues();

                Output.WriteLine($"Read events from PI Point [{pointName}].");
                AssertEventually.True(() =>
                {
                    eventsRead = point.RecordedValuesByCount(start, eventsCount, true, AFBoundaryType.Inside, null, false);

                    if (eventsToWrite.Count != eventsRead.Count)
                    {
                        Output.WriteLine($"The read event count {eventsRead.Count} does not match the written event count {eventsToWrite.Count}.");
                        return false;
                    }
                    else
                    {
                        for (int j = 0; j < eventsCount; j++)
                        {
                            if (!eventsToWrite[j].Value.Equals(eventsRead[j].Value))
                            {
                                Output.WriteLine($"Written event value {AFFixture.DisplayAFValue(eventsToWrite[j])} " +
                                    $"did not match read event value {AFFixture.DisplayAFValue(eventsRead[j])}.");
                                return false;
                            }
                        }
                    }

                    return true;
                },
                $"The events read back do not match the events written to PI Data Archive [{Fixture.PIServer.Name}].");

                // Delete the events
                Output.WriteLine($"Delete events from PI Point [{pointName}].");
                eventsRead.Clear();
                point.UpdateValues(eventsToWrite, AFUpdateOption.Remove);

                AssertEventually.True(() =>
                {
                    eventsRead = point.RecordedValuesByCount(start, eventsCount, true, AFBoundaryType.Inside, null, false);
                    return eventsRead.Count == 0;
                },
                $"The return event count should be 0 after deleting the events, but it was actually {eventsRead.Count}.");
            }
            finally
            {
                // Delete the PI Point to cleanup
                Fixture.DeletePIPoints(pointName, Output);
            }
        }