/// <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}"); } }
/// <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; }