public override UPnPTestStates Run(ICollection otherSubTests, CdsSubTestArgument arg) { CpContentDirectory CDS = this.GetCDS(arg._Device); _Details = new CdsResult_BrowseSortCriteria(); this._TestState = UPnPTestStates.Running; arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, "\""+this.Name + "\" started."); // get the results from the prerequisite tests CdsResult_BrowseAll BROWSE_RESULTS = null; CdsResult_GetSortCapabilities SORTCAPS = null; try { foreach (ISubTest preTest in otherSubTests) { if (preTest.Name == this.PRE_BROWSEALL.Name) { BROWSE_RESULTS = preTest.Details as CdsResult_BrowseAll; } else if (preTest.Name == this.PRE_SORTCAPS.Name) { SORTCAPS = preTest.Details as CdsResult_GetSortCapabilities; } } if (BROWSE_RESULTS == null) { throw new TestException(this._Name + " requires that the \"" + this.PRE_BROWSEALL.Name + "\" test be run as a prerequisite. The results from that test cannot be obtained.", otherSubTests); } if (SORTCAPS == null) { throw new TestException(this._Name + " requires that the \"" + this.PRE_SORTCAPS.Name + "\" test be run as a prerequisite. The results from that test cannot be obtained.", otherSubTests); } } catch (Exception e) { throw new TestException(this._Name + " requires that the \"" + this.PRE_BROWSEALL.Name + "\" and \"" + this.PRE_SORTCAPS+ "\" tests be run before. An error occurred when attempting to obtain the results of those prerequisites.", otherSubTests, e); } _Details.BrowseAllResults = BROWSE_RESULTS; _Details.SortCapsResults = SORTCAPS; UPnPTestStates state = this._TestState; if (BROWSE_RESULTS.LargestContainer == null) { throw new TestException(this.PRE_BROWSEALL.Name + " failed to find the container with the most child objects. " +this._Name+ " requires this value.", BROWSE_RESULTS); } MediaContainer MC = BROWSE_RESULTS.LargestContainer as MediaContainer; if (MC == null) { throw new TestException(this.PRE_BROWSEALL.Name + " has the largest container as type \"" +BROWSE_RESULTS.LargestContainer.GetType().ToString() +"\" when \"" +this.Name+ "\" requires \"" +typeof(MediaContainer).ToString()+ "\".", BROWSE_RESULTS); } ArrayList sortFields = new ArrayList(); if (SORTCAPS.SortCapabilities == "") { //arg.TestGroup.AddEvent(LogImportance.Remark, this.Name, "\""+this.Name+"\" has no sorting capabilities."); } else if (SORTCAPS.SortCapabilities == "*") { sortFields = (ArrayList) BROWSE_RESULTS.PropertyNames.Clone(); } else { sortFields.AddRange ( GetSortFields(SORTCAPS.SortCapabilities) ); } _Details.ExpectedTotalBrowseRequests = 0; _Details.SortFields = sortFields; int fieldCount = sortFields.Count; IList childList = BROWSE_RESULTS.LargestContainer.CompleteList; _Details.ExpectedTotalBrowseRequests = 0;//fieldCount * fieldCount * fieldCount; uint inc = (uint) (childList.Count / 3); int firstInc = (fieldCount / 3); if (firstInc == 0) { firstInc = 1; } for (int numFields = 0; numFields < fieldCount; numFields++) { for (int first = 0; first < fieldCount; first+=firstInc) { //for (uint i=0; i < childList.Count; i+=inc) { _Details.ExpectedTotalBrowseRequests++; } } } // add 1 for an unsorted browse _Details.ExpectedTotalBrowseRequests++; //multiply by 2 because we have 2 rounds to check for consistency in ordered results _Details.ExpectedTotalBrowseRequests *= 2; //calculate time this._ExpectedTestingTime = _Details.ExpectedTotalBrowseRequests * 900; arg.ActiveTests.UpdateTimeAndProgress(0); if (state <= UPnPTestStates.Running) { state = UPnPTestStates.Pass; try { ArrayList round2 = new ArrayList(); //perform the standard unsorted browse BrowseInput input = new BrowseInput(); input.BrowseFlag = CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEDIRECTCHILDREN; input.StartingIndex = 0; input.ObjectID = MC.ID; input.RequestedCount = 0; input.Filter = "*"; input.SortCriteria = ""; CdsBrowseSearchResults br = Browse(input, this, arg, CDS, _Details); Round2 r2 = new Round2(); r2.Input = (BrowseInput) input.Clone(); r2.PreviousResult = br; round2.Add(r2); for (int numFields = 0; numFields < fieldCount; numFields++) { for (int first = 0; first < fieldCount; first+=firstInc) { ArrayList sortSettings = GetSortSettings(sortFields, first, first); input.SortCriteria = GetSortCriteriaString(sortSettings, numFields+first); arg.ActiveTests.UpdateTimeAndProgress(_Details.TotalBrowseRequests * 900); uint ignored; //use this sorter for to determine the expected order of the media objects IMediaSorter sorter = new MediaSorter(true, input.SortCriteria); IList expectedSorted = MC.BrowseSorted(0, 0, sorter, out ignored); br = Browse(input, this, arg, CDS, _Details); arg.ActiveTests.UpdateTimeAndProgress(_Details.TotalBrowseRequests * 900); this.CompareResultsAgainstExpected(br, expectedSorted, ref state, arg, input, false); r2 = new Round2(); r2.Input = (BrowseInput) input.Clone(); r2.PreviousResult = br; round2.Add(r2); } } //do round2 - check for consistency in results foreach (Round2 r in round2) { br = Browse(r.Input, this, arg, CDS, _Details); arg.ActiveTests.UpdateTimeAndProgress(_Details.TotalBrowseRequests * 900); this.CompareResultsAgainstExpected(br, r.PreviousResult.MediaObjects, ref state, arg, r.Input, true); } } catch (TerminateEarly te) { string reason = "\"" +this.Name+ "\" terminating early. Reason => " + te.Message; arg._TestGroup.AddEvent(LogImportance.Critical, this.Name, reason); state = UPnPTestStates.Failed; } } // finish up logging this._TestState = state; StringBuilder sb = new StringBuilder(); sb.AppendFormat("\"{0}\" completed", this.Name); if (this._TestState <= UPnPTestStates.Running) { throw new TestException("\"" +this.Name+ "\" must have a pass/warn/fail result.", this._TestState); } switch (this._TestState) { case UPnPTestStates.Pass: sb.Append(" successfully."); break; case UPnPTestStates.Warn: sb.Append(" with warnings."); break; case UPnPTestStates.Failed: sb.Append(" with a failed result."); break; } arg._TestGroup.AddResult(sb.ToString()); if (this._TestState <= UPnPTestStates.Warn) { if (_Details.TotalBrowseRequests != _Details.ExpectedTotalBrowseRequests) { throw new TestException("TotalBrowseRequests="+_Details.TotalBrowseRequests.ToString()+" ExpectedTotal="+_Details.ExpectedTotalBrowseRequests.ToString(), _Details); } } arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, sb.ToString()); return this._TestState; }
/// <summary> /// Method executes when a control point invokes the ContentDirectory.Search action. /// The method will recursively search all descendent objects and determine if /// the objects match the search criteria. All objects that match the search /// criteria will be included in a flat DIDL-Lite listing of media objects /// in the response. Sort criteria and filter criteria are just applied in /// the same manner as a browse request. /// </summary> /// <param name="containerID">Container to search from.</param> /// <param name="searchCriteria">Valid CDS search criteria string.</param> /// <param name="filter"> /// Comma separated value list of metadata property names to include in the response. /// Return * for all metadata. /// </param> /// <param name="startingIndex">Given the entire possible response set, return a subset beginning with this index in the result set.</param> /// <param name="requestedCount">Given the entire possible response set, return a subset totalling no more than this many.</param> /// <param name="sortCriteria">Specify a comma-separated value list of metadata properties, with a + or - char before each property name to indicate ascending/descending order.</param> /// <param name="Result">DIDL-Lite response for desired result set.</param> /// <param name="numberReturned">Number of media objects returned in the response. 0 if browsing object metadata.</param> /// <param name="totalMatches">Total number of media objects in entire result set. 0 if browsing object metadata.</param> /// <param name="updateID">The UpdateID of the object - ignore if an object.item entry. Applies only to object.container entries.</param> private void SinkCd_Search(System.String containerID, System.String searchCriteria, System.String filter, System.UInt32 startingIndex, System.UInt32 requestedCount, System.String sortCriteria, out System.String Result, out System.UInt32 numberReturned, out System.UInt32 totalMatches, out System.UInt32 updateID) { try { numberReturned = 0; Result = ""; totalMatches = 0; updateID = 0; // Get the container with the ID. // IDvMedia entry = this.GetCdsEntry(containerID); if (entry.IsContainer == false) { throw new Error_NoSuchContainer("("+containerID+")"); } DvMediaContainer container = (DvMediaContainer) entry; // Issue a search from the container. // Search requires a MediaComparer to determine whether an entry matches // against the searchCriteria. // Sorting is optional, but it requires that we traverse the entire subtree // in order to reply properly. // IList entries; if (sortCriteria.Trim() == "") { MediaComparer postfix = new MediaComparer(searchCriteria); entries = container.Search(postfix, startingIndex, requestedCount, out totalMatches); } else { MediaSorter sorter = new MediaSorter(true, sortCriteria); MediaComparer postfix = new MediaComparer(searchCriteria); entries = container.SearchSorted(postfix, sorter, startingIndex, requestedCount, out totalMatches); } for (int rem=0; rem < startingIndex; rem++) { entries.RemoveAt(0); } numberReturned = Convert.ToUInt32(entries.Count); updateID = container.UpdateID; // Get the XML response for this result set. // Be sure to grab the list of base URLs. ArrayList properties = GetFilters(filter); string[] baseUrls = GetBaseUrlsByInterfaces(); Result = BuildXmlRepresentation(baseUrls, properties, entries); } catch (Exception e) { Exception ne = new Exception("MediaServer.SinkCd_Search()", e); throw ne; } this.m_Stats.Search++; this.FireStatsChange(); }
public void CompareResultsAgainstExpected(CdsBrowseSearchResults br, IList expectedResults, ref UPnPTestStates state, CdsSubTestArgument arg, BrowseInput input, bool strictOrder) { if (br.WorstError >= UPnPTestStates.Failed) { throw new TerminateEarly("\"" + this.Name + "\" is terminating early because " +input.PrintBrowseParams()+ " returned with an error or had problems with the DIDL-Lite."); } else { if (br.MediaObjects.Count != expectedResults.Count) { throw new TerminateEarly("\""+this.Name+"\" did a " +input.PrintBrowseParams()+ " and it should have returned "+expectedResults.Count+ " media objects. DIDL-Lite contained " +br.MediaObjects.Count+ " media objects. DIDL-Lite => " + br.Result); } bool warnResults = false; for (int i=0; i < br.MediaObjects.Count; i++) { IUPnPMedia gotThis = (IUPnPMedia) br.MediaObjects[i]; IUPnPMedia expectedMedia = (IUPnPMedia) expectedResults[i]; if (gotThis.ID == expectedMedia.ID) { //arg.TestGroup.AddEvent(LogImportance.Remark, this.Name, "\""+this.Name+"\" did a " +input.PrintBrowseParams()+ " and encountered no errors in the results."); } else { bool failed = false; if ((input.SortCriteria == null) || (input.SortCriteria == "")) { failed = true; } else { // Use this sorter to test for value-equality in situations where the expected order didn't match. // We need to do this because two media objects may be value-equivalent according to a sorting // algorithm, in which case there's no way to really distinguish what order they should be in. IMediaSorter sorter2 = new MediaSorter(false, input.SortCriteria); int cmp = sorter2.Compare(gotThis, expectedMedia); if (cmp != 0) { arg.TestGroup.AddEvent(LogImportance.Medium, this.Name, "\""+this.Name+"\" found media object ID=\""+gotThis.ID+"\" when it expected to find \""+expectedMedia.ID+"\" and they are not equal in their sorted order."); warnResults = true; } else { if (strictOrder == false) { arg.TestGroup.AddEvent(LogImportance.Low, this.Name, "\""+this.Name+"\" found media object ID=\""+gotThis.ID+"\" when it expected to find \""+expectedMedia.ID+"\" but since they are effectively value-equivalent, the ordering is OK."); } else { failed = true; } } } if (failed) { StringBuilder msg = new StringBuilder(); msg.AppendFormat("\"{0}\" did a {1} and the order of object ID's in the result conflicts with previous browse requests."); msg.AppendFormat("\r\n\r\nReceived objects in order by ID: "); int z = 0; foreach (IUPnPMedia em in br.MediaObjects) { if (z > 0) { msg.Append(","); } msg.AppendFormat("\"{0}\"", em.ID); z++; } msg.Append("\r\n\r\nThe expected order by ID is: "); z = 0; foreach (IUPnPMedia em in expectedResults) { if (z > 0) { msg.Append(","); } msg.AppendFormat("\"{0}\"", em.ID); z++; } msg.AppendFormat(".\r\n\r\nDIDL-Lite ==> {0}", br.Result); throw new TerminateEarly(msg.ToString()); } } } if (warnResults == false) { arg.TestGroup.AddEvent(LogImportance.Remark, this.Name, "\""+this.Name+"\" did a " +input.PrintBrowseParams()+ " and encountered no errors or warnings in the results."); } else { StringBuilder msg = new StringBuilder(); msg.AppendFormat("WARNING: \"{0}\" did a {1} and \r\nreceived results in the following order by ID: ", this.Name, input.PrintBrowseParams()); int z = 0; foreach (IUPnPMedia em in br.MediaObjects) { if (z > 0) { msg.Append(","); } msg.AppendFormat("\"{0}\"", em.ID); z++; } msg.Append("\r\n\r\nThe expected order by ID is: "); z = 0; foreach (IUPnPMedia em in expectedResults) { if (z > 0) { msg.Append(","); } msg.AppendFormat("\"{0}\"", em.ID); z++; } msg.AppendFormat(".\r\n\r\nDIDL-Lite ==> {0}", br.Result); // warn state = UPnPTestStates.Warn; arg._TestGroup.AddEvent(LogImportance.Medium, this.Name, msg.ToString()); } } }
/// <summary> /// Method executes when a control point invokes the ContentDirectory.Browse action. /// Depending on the input parameters, the method either returns the metadata /// for the specified object, or the method returns the metadata of all child objects /// if direct children metadata was requested and the specified object is actually /// a container. /// </summary> /// <param name="objectID">Browse the metadata or the children of this object</param> /// <param name="browseFlag">Indicate whether metadata or child object metadata is desired</param> /// <param name="filter">Comma separated value list of metadata properties indicates desired metadata properties to include in response, use * for all.</param> /// <param name="startingIndex">Given the entire possible response set, return a subset beginning with this index in the result set.</param> /// <param name="requestedCount">Given the entire possible response set, return a subset totalling no more than this many.</param> /// <param name="sortCriteria">Specify a comma-separated value list of metadata properties, with a + or - char before each property name to indicate ascending/descending order.</param> /// <param name="Result">DIDL-Lite response for desired result set.</param> /// <param name="numberReturned">Number of media objects returned in the response. 0 if browsing object metadata.</param> /// <param name="totalMatches">Total number of media objects in entire result set. 0 if browsing object metadata.</param> /// <param name="updateID">The UpdateID of the object - ignore if an object.item entry. Applies only to object.container entries.</param> private void SinkCd_Browse(System.String objectID, DvContentDirectory.Enum_A_ARG_TYPE_BrowseFlag browseFlag, System.String filter, System.UInt32 startingIndex, System.UInt32 requestedCount, System.String sortCriteria, out System.String Result, out System.UInt32 numberReturned, out System.UInt32 totalMatches, out System.UInt32 updateID) { try { numberReturned = 0; Result = ""; totalMatches = 0; if (requestedCount == 0) { requestedCount = Convert.ToUInt32(int.MaxValue); } // Get the item identified by the ID, or throw an exception // if the item doesn't exist. // IDvMedia entry = this.GetCdsEntry(objectID); // Issue a browse on the entry if it's a container and we're browing children. // Return the results in entries. Apply sorting if appropriate. // IList entries; if ((entry.IsContainer) && (browseFlag == DvContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEDIRECTCHILDREN)) { DvMediaContainer container = (DvMediaContainer) entry; if (sortCriteria.Trim() == "") { entries = container.Browse(startingIndex, requestedCount, out totalMatches); } else { MediaSorter sorter = new MediaSorter(true, sortCriteria); entries = container.BrowseSorted(startingIndex, requestedCount, sorter, out totalMatches); } numberReturned = Convert.ToUInt32(entries.Count); updateID = container.UpdateID; } else { // We're browsing an item or a container's metadata, so simply set the entry to be // the only return value. // entries = new ArrayList(); entries.Add(entry); totalMatches = 1; numberReturned = 1; IDvMedia dvMedia = (IDvMedia) entry; DvMediaContainer container = dvMedia as DvMediaContainer; if (container == null) { container = (DvMediaContainer) dvMedia.Parent; } updateID = container.UpdateID; } // Get the XML response for this result set. // Be sure to grab the list of base URLs. ArrayList properties = GetFilters(filter); string[] baseUrls = GetBaseUrlsByInterfaces(); Result = BuildXmlRepresentation(baseUrls, properties, entries); } catch (Exception e) { Exception ne = new Exception("MediaServerDevice.SinkCd_Browse()", e); throw ne; } this.m_Stats.Browse++; this.FireStatsChange(); }