/// <summary>
        /// Find if PI messages with a particular ID are logged in the time window.
        /// </summary>
        /// <param name="fixture">The testing fixture.</param>
        /// <param name="startTime">The start time.</param>
        /// <param name="endTime">The end time.</param>
        /// <param name="id">The message id.</param>
        /// <param name="msgText">The message text that to be found in the log.</param>
        /// <returns>Return true if msgs with id and msgText are found in the log; otherwise false.</returns>
        public static bool FindMessagesInLog(PIFixture fixture, string startTime, string endTime, int id, string msgText)
        {
            Contract.Requires(fixture != null);
            Contract.Requires(startTime != null);
            Contract.Requires(endTime != null);
            Contract.Requires(msgText != null);

            string filename = GetPIGETMSGFullFileName();

            startTime = DoubleQuoteIfNeeded(startTime);
            endTime   = DoubleQuoteIfNeeded(endTime);
            msgText   = DoubleQuoteIfNeeded(msgText);

            string arguments = GenerateRemotePIToolArgumentsAsNeeded(fixture.PIServer.ConnectionInfo.Host) + $"-id {id} -st {startTime} -et {endTime} -msg {msgText} -sum";

            // Note: pigetmsg returns exit code 1 even though the command worked.
            // Ignore the exit code and just check the results.
            PIDAExternalToolHelper.RunProgram(filename, arguments, out string results, out _);

            if (!string.IsNullOrEmpty(results))
            {
                string searchText = "Total Messages: ";
                string resultLine = GetFirstLineThatStartsWith(results, searchText);
                if (!string.IsNullOrEmpty(resultLine))
                {
                    string countText = resultLine.Substring(resultLine.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) + resultLine.Length - 1);
                    return(Convert.ToInt32(countText, CultureInfo.InvariantCulture) > 0);
                }
            }

            return(false);
        }
 /// <summary>
 /// Cleans up resources when tests are finished.
 /// </summary>
 public void Dispose()
 {
     AFFixture.Dispose();
     PIFixture.Dispose();
     Client.Dispose();
     ServicePointManager.ServerCertificateValidationCallback = null;
 }
 public void CheckDataArchiveServiceTest(string service)
 {
     using (var fixture = new PIFixture())
     {
         Utils.CheckServiceRunning(fixture.PIServer.ConnectionInfo.Host, service, Output);
     }
 }
        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);
            }
        }
        /// <summary>
        /// Checks if Test Machine and Data Archive Server time differes by more than five seconds.
        /// </summary>
        /// <param name="piServer">Fixture to manage PI connection information.</param>
        /// <param name="output">The output logger used for writing messages.</param>
        public static void CheckTimeDrift(PIFixture piServer, ITestOutputHelper output)
        {
            Contract.Requires(output != null && piServer != null);
            output.WriteLine($"Check to make sure test machine and the Data Archive server time are within tolerance range.");

            const int MaxDriftInSeconds = 5;
            var       serverTime        = piServer.PIServer.ServerTime;
            var       clientTime        = AFTime.Now;
            var       timeDiff          = Math.Abs((clientTime - serverTime).TotalSeconds);

            Assert.True(timeDiff < MaxDriftInSeconds, $"Test machine and the Data Archive server time differs by [{timeDiff}] seconds, which is greater than maximum allowed of {MaxDriftInSeconds} seconds.");
        }
        public void CheckPIAdminsMappingTest()
        {
            using (var piFixture = new PIFixture())
            {
                Output.WriteLine($"Check if current user has required PI Identity of " +
                                 $"[{PIFixture.RequiredPIIdentity}] for the PI Data Archive server [{piFixture.PIServer.Name}].");
                IList <PIIdentity> identities = piFixture.PIServer.CurrentUserIdentities;

                Assert.True(
                    identities.Any(x => x.Name.Equals(PIFixture.RequiredPIIdentity, StringComparison.OrdinalIgnoreCase)),
                    $"The current user does not have the required PI Identity of [{PIFixture.RequiredPIIdentity}], " +
                    $"please add a new mapping to it in PI Data Archive server [{piFixture.PIServer.Name}].");
            }
        }
        public void PIPointTest()
        {
            PIServer piServer       = PIFixture.PIServer;
            string   namePIPointTag = "PIPointTest_Point";

            string[] myPtAttributes = { PICommonPointAttributes.Step, PICommonPointAttributes.PointType };
            try
            {
                // If PI Point exists, delete it
                PIFixture.RemovePIPointIfExists(namePIPointTag, Output);

                // Create attribute values for the PI Point
                var attributeValues = new Dictionary <string, object>
                {
                    { "pointtype", "float32" },
                    { "step", 0 },
                    { "compressing", 0 },
                    { "excmin", 0 },
                    { "excmax", 0 },
                    { "excdev", 0 },
                    { "excdevpercent", 0 },
                    { "shutdown", 0 },
                };

                // Create PI Point
                Output.WriteLine($"Creating PI Point {namePIPointTag} with custom attributes.");
                var point = piServer.CreatePIPoint(namePIPointTag, attributeValues);

                // Update
                Output.WriteLine($"Confirm PI Point [{namePIPointTag}] was created with correct custom attributes.");
                var returnedPoint = PIPoint.FindPIPoint(piServer, namePIPointTag);
                Assert.True(returnedPoint != null, $"Could not find PI Point [{namePIPointTag}] on Data Archive [{piServer}].");
                var originalAttributes = returnedPoint.GetAttributes(myPtAttributes);
                Assert.True(originalAttributes.Count > 0, $"Could not find any attributes for PI Point [{namePIPointTag}].");
                Assert.False(Convert.ToBoolean(originalAttributes[PICommonPointAttributes.Step], CultureInfo.InvariantCulture),
                             $"Expected the Step PI Point attribute to be originally false for PI Point [{namePIPointTag}].");
                var pointType = originalAttributes[PICommonPointAttributes.PointType].ToString();
                Assert.True(pointType.Equals("Float32", StringComparison.OrdinalIgnoreCase),
                            $"Expected the Point Type for PI Point [{namePIPointTag}] to be Float32, was actually [{pointType}].");

                Output.WriteLine($"Setting Step PI Point attribute to true for {namePIPointTag}.");
                returnedPoint.SetAttribute(PICommonPointAttributes.Step, true);
                returnedPoint.SaveAttributes(new string[] { PICommonPointAttributes.Step });
                Assert.True(returnedPoint.Step, $"Expected the Step PI Point attribute to be true for PI Point [{namePIPointTag}] after being set.");
            }
            finally
            {
                PIFixture.DeletePIPoints(namePIPointTag, Output);
            }
        }
        public void CheckProductVersion()
        {
            Output.WriteLine($"AFSDK Version: {AF.AFGlobalSettings.SDKVersion}");
            using (var affixture = new AFFixture())
            {
                Assert.True(affixture.PISystem != null, $"AF Server [{affixture.PISystem}] could not be found.");
                Output.WriteLine($"AF Server Version: {affixture.PISystem.ServerVersion}");
            }

            using (var pifixture = new PIFixture())
            {
                Assert.True(pifixture.PIServer != null, $"PI Server [{pifixture.PIServer}] could not be found.");
                Output.WriteLine($"PI Data Archive Version: {pifixture.PIServer.ServerVersion}");
            }
        }
Example #9
0
        /// <summary>
        /// Sends a number of events to each PI Point in a PI Point list.
        /// </summary>
        /// <remarks>
        /// By default the events' timestamp increments by 1 second and the values are calculated from the timestamps.
        /// If the eventsToSend parameter is specified then those events are used explicitly.
        /// </remarks>
        /// <param name="startTime">Start time used for event time stamps.</param>
        /// <param name="eventCount">Number of events to write to PI Data Archive.</param>
        /// <param name="piPoints">List of PI Points to which events will be written.</param>
        /// <param name="eventsToSend">OPTIONAL events to use (instead of being generated by routine).</param>
        public void SendTimeBasedPIEvents(AFTime startTime, int eventCount, List <PIPoint> piPoints, Dictionary <DateTime, double> eventsToSend = null)
        {
            // Build PI events as needed
            if (eventsToSend == null)
            {
                DateTime st = startTime;
                eventsToSend = new Dictionary <DateTime, double>();
                for (int i = 0; i < eventCount; i++)
                {
                    DateTime ts = st.AddSeconds(i);
                    eventsToSend.Add(ts, PIFixture.ConvertTimeStampToFloat(ts));
                }
            }

            object[]        vals       = eventsToSend.Values.Cast <object>().ToArray();
            DateTime[]      timeStamps = eventsToSend.Keys.ToArray();
            AFValueStatus[] statuses   = Enumerable.Range(0, eventCount).Select(_ => AFValueStatus.Good).ToArray();
            UOM             nullUOM    = null;

            var newValues = new List <AFValues>();
            var pointList = new PIPointList(piPoints);

            foreach (PIPoint pt in pointList)
            {
                var newAFValues = new AFValues(vals, timeStamps, statuses, nullUOM)
                {
                    PIPoint = pt,
                };
                newValues.Add(newAFValues);
            }

            if (newValues.Count == 0)
            {
                return;
            }

            // Send PI events
            foreach (AFValues values in newValues)
            {
                AFErrors <AFValue> errors = PIServer.UpdateValues(values.ToList(), AFUpdateOption.NoReplace);
                if (errors != null)
                {
                    throw errors.Errors.First().Value;
                }
            }
        }
        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);
            }
        }
        /// <summary>
        /// Gets the machine name of service.
        /// </summary>
        /// <param name="settingName">Name of the setting for the service in app config settings file.</param>
        /// <returns>Name of machine running that service.</returns>
        public static string GetMachineName(string settingName)
        {
            switch (settingName)
            {
            case "PIDataArchive":
                using (var pifixture = new PIFixture())
                    return(pifixture.PIServer.ConnectionInfo.Host);

            case "AFServer":
                using (var affixture = new AFFixture())
                    return(affixture.PISystem.ConnectionInfo.Host);

            case "PIAnalysisService":
                return(Settings.PIAnalysisService);

            case "PINotificationsService":
                return(Settings.PINotificationsService);

            case "PIWebAPI":
                return(Settings.PIWebAPI);

            case "PIWebAPICrawler":
                return(Settings.PIWebAPICrawler);

            case "PIVisionServer":
                if (string.IsNullOrWhiteSpace(Settings.PIVisionServer))
                {
                    return(string.Empty);
                }
                return(Settings.PIVisionServer.Split('/')[2].Split(':')[0]);

            case "PIManualLogger":
                return(Settings.PIManualLogger);

            default:
                return($"Invalid setting name '{settingName}' specified.");
            }
        }
        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 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);
            }
        }
 /// <summary>
 /// Constructor for PITests Class
 /// </summary>
 /// <param name="output">The output logger used for writing messages.</param>
 /// <param name="afFixture">AF Fixture to manage connection and AF related helper functions.</param>
 /// <param name="piFixture">PI Fixture to manage connection and Data Archive related helper functions.</param>
 public AFPITests(ITestOutputHelper output, AFFixture afFixture, PIFixture piFixture)
 {
     Output    = output;
     AFFixture = afFixture;
     PIFixture = piFixture;
 }