Publishing results of generic type <T> for Results.Publish and OnResultPublished
To extend the capabilities of publishing results to ResultListeners by creating a new signature for Publish and a new override for OnResultPublished.
Different database storage systems can take advantage of the unique features of their storage engines to simplify storage, retrieval and reporting of result data.
Using MongoDB, for instance, would simplify complex data storage, and permit blob storage of very large array data and image files created by test steps. Reporting and analysis applications would then be able to create measurement reports with rich data. A typical scenario is when creating a single DUT test report of all the measurement data for many test modes, for example, FCC and ETSI compliance tests in a tabulated format with images.
A typical report data output can be found from page 20 onwards at https://fccid.io/2ABCB-RPI3BP/Test-Report/Test-Report-2-4GHz-3777894.
Current publishing implementations permit arrays, key-value pairs and custom classes because these are converted into ResultTable objects which are passed to ResultListeners via OnResultPublished. This restricts images and other complex data sharing the same publish call. Say I have a test step that produces a power and PSD result (as they are done in the same measurement). Each result is independent and is analysed and reported independently and thus is realised as two publish calls. Each are a scalar result and can be published as normal with extra columns for limits, the screen image file, etc... When the ResultListener gets this data it sees it as a table with rows and columns. Because there is no 'result' API, the ResultListener cannot separate the data to decide where or how it should be stored. The data could have a column named 'ImageFile' that the ResultListener scans for, extracts the local path to the file, gets the file and stores it in a blob. This is achievable and loosely an API of sorts but it is not strongly-typed that hides the functionality from other listeners. In addition to the analyser screen image, I also want to store the trace data, analyser settings and limits. All new data that wasn't available entering the test step and therefore cannot be added to ResulParameters until the test step run has completed. The results have the key to the test step run and therefore its ResultParameters, as seen in the Results Viewer. If the ResultTable object had additional fields for limits, image files, data, etc. then all ResultListeners would understand what to do with the data.
What if the ResultListener could extend the publishing capabilities with a complex custom class? Publish(T result) where T is passed all the way through to the ResultListner for processing, or by implementing a Result API. The ResultListener would need access to type in order to serialize it to a BSON document without the need for complex reflection. How could this be done? Does it present problems, i.e, is the test step creating only useable with ResultListners supporting , or would a custom serializer be needed for each or a sophisticated serializer for any ? Can a 'Result' API be created?
Is there a show-stopper issue with tying this approach rather than solely using the ResultTable? Would it mean test steps are tied to specific ResultListeners?
MongoDB simplifies the serialization and storage of classes as BSON document structures (similar to JSON), that is also true for deserialization and thus beneficial to reporting and analysis applications also.
The snippet below could be a Result API showing how two result classes implementing the result base class but with different result tables. Note, the base class uses OpenTap ResultParameters transformed into serializable List. The TestStepResult base class provides key fields that the ResultListener can use to shape and direct data correctly.
public class ObwStepResult : TestStepResult
{
public TraceTable ResultAsTable { get; set; }
// Add more as needed
}
public class BurstResult : TestStepResult
{
public BurstTable ResultAsTable { get; set; }
// Add more as needed
}
public class TraceTable
{
public long[] Frequency { get; set; }
public double[] Level { get; set; }
}
public class BurstTable
{
public int[] BurstId { get; set; }
public dynamic[] StartTime { get; set; }
public double[] TxOnDuration { get; set; }
public double[] GapDuration { get; set; }
public double[] AveragePower { get; set; }
public double[] PeakPower { get; set; }
}
public abstract class TestStepResult
{
public string Name { get; set; }
public dynamic LowerLimit { get; set; }
public dynamic UpperLimit { get; set; }
public dynamic Result { get; set; }
public string Units { get; set; }
public Verdict Verdict { get; set; }
public List<Parameter> Parameters { get; set; }
public Image ResultAsImage { get; set; }
}
public class Parameter
{
public string Name { get; set; }
public string Group { get; set; }
public int ParentLevel { get; set; }
public string MacroName { get; set; }
public bool IsMetaData { get; set; }
public dynamic Value { get; set; }
}