/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool?Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool?passed = true; info = null; bool?result; List <ExtensionRuleResultDetail> details = new List <ExtensionRuleResultDetail>(); // call helper method ExtensionRuleViolationInfo info1 = null; HttpStatusCode? selectResult = VerificationHelper.VerifySelect(context, out result, out info1); if (info1 != null) { info1.SetDetailsName(this.Name); details.AddRange(info1.Details); } if (false == result || !(selectResult.HasValue && (selectResult.Value == HttpStatusCode.OK || selectResult.Value == HttpStatusCode.NotImplemented))) { passed = false; } ExtensionRuleViolationInfo info2 = null; HttpStatusCode? searchResult = VerificationHelper.VerifySearch(context, out result, out info2); if (info2 != null) { info2.SetDetailsName(this.Name); details.AddRange(info2.Details); } if (false == result || !(searchResult.HasValue && (searchResult.Value == HttpStatusCode.OK || searchResult.Value == HttpStatusCode.NotImplemented))) { passed = false; } ExtensionRuleViolationInfo info3 = null; HttpStatusCode? filterResult = VerificationHelper.VerifyLambdaOperators(context, LambdaOperatorType.All, out result, out info3); if (info3 != null) { info3.SetDetailsName(this.Name); details.AddRange(info3.Details); } if (false == result || !(filterResult.HasValue && (filterResult.Value == HttpStatusCode.OK || filterResult.Value == HttpStatusCode.NotImplemented))) { passed = false; } ExtensionRuleViolationInfo info4 = null; HttpStatusCode? countResult = VerificationHelper.VerifyCount(context, out result, out info4); if (info4 != null) { info4.SetDetailsName(this.Name); details.AddRange(info4.Details); } if (false == result || !(countResult.HasValue && (countResult.Value == HttpStatusCode.OK || countResult.Value == HttpStatusCode.NotImplemented))) { passed = false; } ExtensionRuleViolationInfo info5 = null; HttpStatusCode? skipResult = VerificationHelper.VerifySkip(context, out result, out info5); if (info5 != null) { info5.SetDetailsName(this.Name); details.AddRange(info5.Details); } if (false == result || !(skipResult.HasValue && (skipResult.Value == HttpStatusCode.OK || skipResult.Value == HttpStatusCode.NotImplemented))) { passed = false; } ExtensionRuleViolationInfo info6 = null; HttpStatusCode? topResult = VerificationHelper.VerifyTop(context, out result, out info6); if (info6 != null) { info6.SetDetailsName(this.Name); details.AddRange(info6.Details); } if (false == result || !(topResult.HasValue && (topResult.Value == HttpStatusCode.OK || topResult.Value == HttpStatusCode.NotImplemented))) { passed = false; } ExtensionRuleViolationInfo info7 = null; HttpStatusCode? orderbyResult = VerificationHelper.VerifySortEntities(context, SortedType.ASC, out result, out info7); if (info7 != null) { info7.SetDetailsName(this.Name); details.AddRange(info7.Details); } if (false == result || !(orderbyResult.HasValue && (orderbyResult.Value == HttpStatusCode.OK || orderbyResult.Value == HttpStatusCode.NotImplemented))) { passed = false; } if (passed == null) { passed = true; } info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload, details); return(passed); }
private void TestDirectorySetAttribute_Restart( int bigFileSizeInKB, int smallFileSizeInKB, int bigFileNum, int smallFileNum, Action <DirNode> bigFileDirAddFileAction, Action <DirNode> smallFileDirAddFileAction, SetAttributesCallbackAsync setAttributesCallback = null, Action <DMLibDataInfo> sourceDataInfoDecorator = null) { int totalFileNum = bigFileNum + smallFileNum; long totalSizeInBytes = ((bigFileSizeInKB * bigFileNum) + (smallFileSizeInKB * smallFileNum)) * 1024; DMLibDataInfo sourceDataInfo = new DMLibDataInfo(string.Empty); DirNode bigFileDirNode = new DirNode("big"); DirNode smallFileDirNode = new DirNode("small"); sourceDataInfo.RootNode.AddDirNode(bigFileDirNode); sourceDataInfo.RootNode.AddDirNode(smallFileDirNode); bigFileDirAddFileAction(bigFileDirNode); smallFileDirAddFileAction(smallFileDirNode); CancellationTokenSource tokenSource = new CancellationTokenSource(); TransferItem transferItem = null; var options = new TestExecutionOptions <DMLibDataInfo> { LimitSpeed = true, IsDirectoryTransfer = true }; using (Stream journalStream = new MemoryStream()) { bool isStreamJournal = random.Next(0, 2) == 0; var transferContext = isStreamJournal ? new DirectoryTransferContext(journalStream) : new DirectoryTransferContext(); transferContext.SetAttributesCallbackAsync = setAttributesCallback; var progressChecker = new ProgressChecker(totalFileNum, totalSizeInBytes, totalFileNum, null, 0, totalSizeInBytes); transferContext.ProgressHandler = progressChecker.GetProgressHandler(); var eventChecker = new TransferEventChecker(); eventChecker.Apply(transferContext); transferContext.FileFailed += (sender, e) => { Helper.VerifyCancelException(e.Exception); }; options.TransferItemModifier = (fileName, item) => { dynamic dirOptions = DefaultTransferDirectoryOptions; dirOptions.Recursive = true; item.Options = dirOptions; item.CancellationToken = tokenSource.Token; item.TransferContext = transferContext; transferItem = item; }; TransferCheckpoint firstCheckpoint = null, secondCheckpoint = null; options.AfterAllItemAdded = () => { // Wait until there are data transferred progressChecker.DataTransferred.WaitOne(); if (!isStreamJournal) { // Store the first checkpoint firstCheckpoint = transferContext.LastCheckpoint; } Thread.Sleep(1000); // Cancel the transfer and store the second checkpoint tokenSource.Cancel(); }; // Cancel and store checkpoint for resume var result = this.ExecuteTestCase(sourceDataInfo, options); if (progressChecker.FailedFilesNumber <= 0) { Test.Error("Verify file number in progress. Failed: {0}", progressChecker.FailedFilesNumber); } TransferCheckpoint firstResumeCheckpoint = null, secondResumeCheckpoint = null; if (!isStreamJournal) { secondCheckpoint = transferContext.LastCheckpoint; Test.Info("Resume with the second checkpoint first."); firstResumeCheckpoint = secondCheckpoint; secondResumeCheckpoint = firstCheckpoint; } // resume with firstResumeCheckpoint TransferItem resumeItem = transferItem.Clone(); progressChecker.Reset(); TransferContext resumeContext = null; if (isStreamJournal) { resumeContext = new DirectoryTransferContext(journalStream) { ProgressHandler = progressChecker.GetProgressHandler() }; } else { resumeContext = new DirectoryTransferContext(DMLibTestHelper.RandomReloadCheckpoint(firstResumeCheckpoint)) { ProgressHandler = progressChecker.GetProgressHandler() }; } resumeContext.SetAttributesCallbackAsync = setAttributesCallback; eventChecker.Reset(); eventChecker.Apply(resumeContext); resumeItem.TransferContext = resumeContext; result = this.RunTransferItems(new List <TransferItem>() { resumeItem }, new TestExecutionOptions <DMLibDataInfo>()); sourceDataInfoDecorator?.Invoke(sourceDataInfo); VerificationHelper.VerifyFinalProgress(progressChecker, totalFileNum, 0, 0); VerificationHelper.VerifySingleTransferStatus(result, totalFileNum, 0, 0, totalSizeInBytes); VerificationHelper.VerifyTransferSucceed(result, sourceDataInfo); if (!isStreamJournal) { // resume with secondResumeCheckpoint resumeItem = transferItem.Clone(); progressChecker.Reset(); resumeContext = new DirectoryTransferContext(DMLibTestHelper.RandomReloadCheckpoint(secondResumeCheckpoint)) { ProgressHandler = progressChecker.GetProgressHandler(), // Need this overwrite callback since some files is already transferred to destination ShouldOverwriteCallbackAsync = DMLibInputHelper.GetDefaultOverwiteCallbackY(), SetAttributesCallbackAsync = setAttributesCallback }; eventChecker.Reset(); eventChecker.Apply(resumeContext); resumeItem.TransferContext = resumeContext; result = this.RunTransferItems(new List <TransferItem>() { resumeItem }, new TestExecutionOptions <DMLibDataInfo>()); VerificationHelper.VerifyFinalProgress(progressChecker, totalFileNum, 0, 0); VerificationHelper.VerifySingleTransferStatus(result, totalFileNum, 0, 0, totalSizeInBytes); VerificationHelper.VerifyTransferSucceed(result, sourceDataInfo); } } }
public void DirectoryOverwriteDestination() { string destExistYName = "destExistY"; string destExistNName = "destExistN"; string destNotExistYName = "destNotExistY"; DMLibDataInfo sourceDataInfo = new DMLibDataInfo(string.Empty); DMLibDataHelper.AddOneFileInBytes(sourceDataInfo.RootNode, destExistYName, 1024); DMLibDataHelper.AddOneFileInBytes(sourceDataInfo.RootNode, destExistNName, 1024); DMLibDataHelper.AddOneFileInBytes(sourceDataInfo.RootNode, destNotExistYName, 1024); DMLibDataInfo destDataInfo = new DMLibDataInfo(string.Empty); DMLibDataHelper.AddOneFileInBytes(destDataInfo.RootNode, destExistYName, 1024); DMLibDataHelper.AddOneFileInBytes(destDataInfo.RootNode, destExistNName, 1024); TransferContext transferContext = new TransferContext(); transferContext.OverwriteCallback = (string sourcePath, string destinationPath) => { if (sourcePath.EndsWith(destExistNName)) { return(false); } else { return(true); } }; int skipCount = 0; int successCount = 0; transferContext.FileSkipped += (object sender, TransferEventArgs args) => { Interlocked.Increment(ref skipCount); TransferException transferException = args.Exception as TransferException; Test.Assert(transferException != null, "Verify the exception is a TransferException"); VerificationHelper.VerifyTransferException(transferException, TransferErrorCode.NotOverwriteExistingDestination, "Skiped file", destExistNName); }; transferContext.FileTransferred += (object sender, TransferEventArgs args) => { Interlocked.Increment(ref successCount); }; var options = new TestExecutionOptions <DMLibDataInfo>(); options.IsDirectoryTransfer = true; if (DMLibTestContext.DestType != DMLibDataType.Stream) { options.DestTransferDataInfo = destDataInfo; } options.TransferItemModifier = (fileNode, transferItem) => { transferItem.TransferContext = transferContext; dynamic transferOptions = DefaultTransferDirectoryOptions; transferOptions.Recursive = true; transferItem.Options = transferOptions; }; var result = this.ExecuteTestCase(sourceDataInfo, options); DMLibDataInfo expectedDataInfo = new DMLibDataInfo(string.Empty); if (DMLibTestContext.DestType != DMLibDataType.Stream) { expectedDataInfo.RootNode.AddFileNode(sourceDataInfo.RootNode.GetFileNode(destExistYName)); expectedDataInfo.RootNode.AddFileNode(destDataInfo.RootNode.GetFileNode(destExistNName)); expectedDataInfo.RootNode.AddFileNode(sourceDataInfo.RootNode.GetFileNode(destNotExistYName)); } else { expectedDataInfo = sourceDataInfo; } // Verify transfer result Test.Assert(DMLibDataHelper.Equals(expectedDataInfo, result.DataInfo), "Verify transfer result."); // Verify exception if (DMLibTestContext.DestType != DMLibDataType.Stream) { VerificationHelper.VerifySingleTransferStatus(result, 2, 1, 0, 1024 * 2); Test.Assert(successCount == 2, "Verify success transfers"); Test.Assert(skipCount == 1, "Verify skipped transfer"); } else { VerificationHelper.VerifySingleTransferStatus(result, 3, 0, 0, 1024 * 3); Test.Assert(successCount == 3, "Very all transfers are success"); Test.Assert(skipCount == 0, "Very no transfer is skipped"); } }
public void OverwriteDestination() { string destExistYName = "destExistY"; string destExistNName = "destExistN"; string destNotExistYName = "destNotExistY"; DMLibDataInfo sourceDataInfo = new DMLibDataInfo(string.Empty); DMLibDataHelper.AddOneFileInBytes(sourceDataInfo.RootNode, destExistYName, 1024); DMLibDataHelper.AddOneFileInBytes(sourceDataInfo.RootNode, destExistNName, 1024); DMLibDataHelper.AddOneFileInBytes(sourceDataInfo.RootNode, destNotExistYName, 1024); DMLibDataInfo destDataInfo = new DMLibDataInfo(string.Empty); DMLibDataHelper.AddOneFileInBytes(destDataInfo.RootNode, destExistYName, 1024); DMLibDataHelper.AddOneFileInBytes(destDataInfo.RootNode, destExistNName, 1024); var options = new TestExecutionOptions <DMLibDataInfo>(); if (DMLibTestContext.DestType != DMLibDataType.Stream) { options.DestTransferDataInfo = destDataInfo; } options.TransferItemModifier = (fileNode, transferItem) => { string fileName = fileNode.Name; TransferContext transferContext = new TransferContext(); if (fileName.Equals(destExistYName)) { transferContext.OverwriteCallback = DMLibInputHelper.GetDefaultOverwiteCallbackY(); } else if (fileName.Equals(destExistNName)) { transferContext.OverwriteCallback = DMLibInputHelper.GetDefaultOverwiteCallbackN(); } else if (fileName.Equals(destNotExistYName)) { transferContext.OverwriteCallback = DMLibInputHelper.GetDefaultOverwiteCallbackY(); } transferItem.TransferContext = transferContext; }; var result = this.ExecuteTestCase(sourceDataInfo, options); DMLibDataInfo expectedDataInfo = new DMLibDataInfo(string.Empty); if (DMLibTestContext.DestType != DMLibDataType.Stream) { expectedDataInfo.RootNode.AddFileNode(sourceDataInfo.RootNode.GetFileNode(destExistYName)); expectedDataInfo.RootNode.AddFileNode(destDataInfo.RootNode.GetFileNode(destExistNName)); expectedDataInfo.RootNode.AddFileNode(sourceDataInfo.RootNode.GetFileNode(destNotExistYName)); } else { expectedDataInfo = sourceDataInfo; } // Verify transfer result Test.Assert(DMLibDataHelper.Equals(expectedDataInfo, result.DataInfo), "Verify transfer result."); // Verify exception if (DMLibTestContext.DestType != DMLibDataType.Stream) { Test.Assert(result.Exceptions.Count == 1, "Verify there's only one exceptions."); TransferException transferException = result.Exceptions[0] as TransferException; Test.Assert(transferException != null, "Verify the exception is a TransferException"); VerificationHelper.VerifyTransferException(transferException, TransferErrorCode.NotOverwriteExistingDestination, "Skiped file", destExistNName); } }
/// <summary> /// Verify Common.Core.4623 /// </summary> /// <param name="context">Service context</param> /// <param name="info">out parameter to return violation information when rule fail</param> /// <returns>true if rule passes; false otherwise</returns> public override bool?Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool?passed = null; info = null; // Single primitive individual property is not allowed to have instance annotation. if (VerificationHelper.IsIndividualPropertySinglePrimitiveType(context.ResponsePayload, context.PayloadType)) { return(null); } XmlDocument xmlDoc = new XmlDocument(); // Test Data // Url:http://services.odata.org/V4/OData/OData.svc/Products(0)/Description?$format=xml // xmlDoc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><m:value m:context=\"http://services.odata.org/V4/OData/OData.svc/$metadata#Products(0)/Description\" xmlns:atom=\"http://www.w3.org/2005/Atom\" xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" xmlns:georss=\"http://www.georss.org/georss\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\">Whole grain bread <m:annotation atom:term=\"ODataDemo.Product.Display\" m:target=\"Description\" m:type=\"Boolean\">true</m:annotation></m:value>"); xmlDoc.LoadXml(context.ResponsePayload); XmlNodeList annotationElements = xmlDoc.SelectNodes(@"//*[local-name()='annotation']", ODataNamespaceManager.Instance); foreach (XmlNode annotatEle in annotationElements) { if (annotatEle.Attributes["null", Constants.NSMetadata] != null && annotatEle.Attributes["null", Constants.NSMetadata].Value.Equals("true")) { return(null); } string content = annotatEle.InnerText; if (annotatEle.Attributes["type", Constants.NSMetadata] != null) { string typeName = annotatEle.Attributes["type", Constants.NSMetadata].Value; if (!typeName.Contains(".")) { typeName = "Edm." + typeName; } if (EdmTypeManager.IsEdmSimpleType(typeName)) { IEdmType edmType = EdmTypeManager.GetEdmType(typeName); if (edmType.IsGoodWith(content)) { passed = true; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); break; } } } } return(passed); }
/// <summary> /// Process the request from WeChat. /// This method can be called from inside a POST method on any Controller implementation. /// </summary> /// <param name="httpRequest">The HTTP request object, typically in a POST handler by a Controller.</param> /// <param name="httpResponse">The HTTP response object.</param> /// <param name="bot">The bot implementation.</param> /// <param name="secretInfo">The secret info provide by WeChat.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects /// or threads to receive notice of cancellation.</param> /// <returns>A task that represents the work queued to execute.</returns> public async Task ProcessAsync(HttpRequest httpRequest, HttpResponse httpResponse, IBot bot, SecretInfo secretInfo, CancellationToken cancellationToken = default(CancellationToken)) { _logger.LogInformation("Receive a new request from WeChat."); if (httpRequest == null) { throw new ArgumentNullException(nameof(httpRequest)); } if (httpResponse == null) { throw new ArgumentNullException(nameof(httpResponse)); } if (bot == null) { throw new ArgumentNullException(nameof(bot)); } if (secretInfo == null) { throw new ArgumentNullException(nameof(secretInfo)); } if (!VerificationHelper.VerifySignature(secretInfo.WebhookSignature, secretInfo.Timestamp, secretInfo.Nonce, _settings.Token)) { throw new UnauthorizedAccessException("Signature verification failed."); } // Return echo string when request is setting up the endpoint. if (!string.IsNullOrEmpty(secretInfo.EchoString)) { await httpResponse.WriteAsync(secretInfo.EchoString, cancellationToken).ConfigureAwait(false); return; } // Directly return OK header to prevent WeChat from retrying. if (!_settings.PassiveResponseMode) { httpResponse.StatusCode = (int)HttpStatusCode.OK; httpResponse.ContentType = "text/event-stream"; await httpResponse.WriteAsync(string.Empty).ConfigureAwait(false); await httpResponse.Body.FlushAsync().ConfigureAwait(false); } try { var wechatRequest = GetRequestMessage(httpRequest.Body, secretInfo); var wechatResponse = await ProcessWeChatRequest( wechatRequest, bot.OnTurnAsync, cancellationToken).ConfigureAwait(false); // Reply WeChat(User) request have two ways, set response in http response or use background task to process the request async. if (_settings.PassiveResponseMode) { httpResponse.StatusCode = (int)HttpStatusCode.OK; httpResponse.ContentType = "text/xml"; var xmlString = WeChatMessageFactory.ConvertResponseToXml(wechatResponse); await httpResponse.WriteAsync(xmlString).ConfigureAwait(false); } } catch (Exception ex) { _logger.LogError(ex, "Process WeChat request failed."); throw; } }
public void DirectoryForceOverwriteTest() { string destExistName = "destExist"; string destNotExistName = "destNotExist"; DMLibDataInfo sourceDataInfo = new DMLibDataInfo(string.Empty); DMLibDataHelper.AddOneFileInBytes(sourceDataInfo.RootNode, destExistName, 1024); DMLibDataHelper.AddOneFileInBytes(sourceDataInfo.RootNode, destNotExistName, 1024); DMLibDataInfo destDataInfo = new DMLibDataInfo(string.Empty); DMLibDataHelper.AddOneFileInBytes(destDataInfo.RootNode, destExistName, 1024); TransferContext transferContext = new DirectoryTransferContext(); transferContext.ShouldOverwriteCallbackAsync = TransferContext.ForceOverwrite; int skipCount = 0; int successCount = 0; transferContext.FileSkipped += (object sender, TransferEventArgs args) => { Interlocked.Increment(ref skipCount); }; transferContext.FileTransferred += (object sender, TransferEventArgs args) => { Interlocked.Increment(ref successCount); }; var options = new TestExecutionOptions <DMLibDataInfo>(); options.IsDirectoryTransfer = true; if (DMLibTestContext.DestType != DMLibDataType.Stream) { options.DestTransferDataInfo = destDataInfo; } if (IsCloudService(DMLibTestContext.DestType)) { SharedAccessPermissions permissions; if (DMLibTestContext.CopyMethod == DMLibCopyMethod.ServiceSideAsyncCopy) { permissions = SharedAccessPermissions.Write | SharedAccessPermissions.Read; } else { permissions = SharedAccessPermissions.Write; } StorageCredentials destSAS = new StorageCredentials(DestAdaptor.GenerateSAS(permissions, (int)new TimeSpan(1, 0, 0, 0).TotalSeconds)); options.DestCredentials = destSAS; } options.TransferItemModifier = (fileNode, transferItem) => { transferItem.TransferContext = transferContext; dynamic transferOptions = DefaultTransferDirectoryOptions; transferOptions.Recursive = true; transferItem.Options = transferOptions; }; var result = this.ExecuteTestCase(sourceDataInfo, options); // Verify transfer result Test.Assert(DMLibDataHelper.Equals(sourceDataInfo, result.DataInfo), "Verify transfer result."); VerificationHelper.VerifySingleTransferStatus(result, 2, 0, 0, 1024 * 2); Test.Assert(successCount == 2, "Verify success transfers"); Test.Assert(skipCount == 0, "Verify skipped transfer"); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool?Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool svcDocResult = false; bool metadataResult = false; bool feedAndEntryResult = false; bool referenceResult = false; bool propertyResult = false; bool collectionCountResult = false; bool derivedTypeResult = false; bool mediaStreamResult = false; bool crossJoinResult = false; bool allEntitiesResult = false; ExtensionRuleViolationInfo infoForOne = null; List <ExtensionRuleResultDetail> details = new List <ExtensionRuleResultDetail>(); svcDocResult = VerificationHelper.VerifySvcDoc(context, out infoForOne); if (infoForOne != null) { details.AddRange(infoForOne.Details); } metadataResult = VerificationHelper.VerifyMetadata(context, out infoForOne); if (infoForOne != null) { details.AddRange(infoForOne.Details); } feedAndEntryResult = VerificationHelper.VerifyFeedAndEntry(context, out infoForOne); if (infoForOne != null) { details.AddRange(infoForOne.Details); } referenceResult = VerificationHelper.VerifyReference(context, out infoForOne); if (infoForOne != null) { details.AddRange(infoForOne.Details); } propertyResult = VerificationHelper.VerifyPropertyAndValue(context, out infoForOne); if (infoForOne != null) { details.AddRange(infoForOne.Details); } collectionCountResult = VerificationHelper.VerifyCollectionCount(context, out infoForOne); if (infoForOne != null) { details.AddRange(infoForOne.Details); } derivedTypeResult = VerificationHelper.VerifyDerivedType(context, out infoForOne); if (infoForOne != null) { details.AddRange(infoForOne.Details); } mediaStreamResult = VerificationHelper.VerifyMediaStream(context, out infoForOne); if (infoForOne != null) { details.AddRange(infoForOne.Details); } crossJoinResult = VerificationHelper.VerifyCrossJoin(context, out infoForOne); if (infoForOne != null) { details.AddRange(infoForOne.Details); } allEntitiesResult = VerificationHelper.VerifyAllEntities(context, out infoForOne); if (infoForOne != null) { details.AddRange(infoForOne.Details); } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, details); info.SetDetailsName(this.Name); return(svcDocResult && metadataResult && feedAndEntryResult && referenceResult && propertyResult && collectionCountResult && derivedTypeResult && mediaStreamResult && crossJoinResult && allEntitiesResult); }
/// <summary> /// Verify Common.Core.4628 /// </summary> /// <param name="context">Service context</param> /// <param name="info">out parameter to return violation information when rule fail</param> /// <returns>true if rule passes; false otherwise</returns> public override bool?Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool?passed = null; info = null; // Single primitive individual property is not allowed to have instance annotation. if (VerificationHelper.IsIndividualPropertySinglePrimitiveType(context.ResponsePayload, context.PayloadType)) { return(null); } XmlDocument xmlDoc = new XmlDocument(); // Test Data // Url:http://services.odata.org/V4/OData/OData.svc/Products(0)/Description?$format=xml or http://services.odata.org/V4/OData/OData.svc/Persons(0)?$format=atom // xmlDoc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><m:value m:context=\"http://services.odata.org/V4/OData/OData.svc/$metadata#Products(0)/Description\" xmlns:atom=\"http://www.w3.org/2005/Atom\" xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" xmlns:georss=\"http://www.georss.org/georss\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\">Whole grain bread <m:annotation atom:term=\"com.contoso.address\" m:type=\"#ODataDemo.Address\"><d:Street>2817 Milton Dr.</d:Street><d:City>Albuquerque</d:City><d:State>NM</d:State><d:ZipCode>87110</d:ZipCode><d:Country>USA</d:Country></m:annotation></m:value>"); xmlDoc.LoadXml(context.ResponsePayload); XmlNodeList annotationElements = xmlDoc.SelectNodes(@"//*[local-name()='annotation']", ODataNamespaceManager.Instance); passed = true; foreach (XmlNode annotatEle in annotationElements) { bool isStructuredValue = false; if (annotatEle.ChildNodes != null && annotatEle.ChildNodes.Count > 1) { isStructuredValue = true; foreach (XmlNode ele in annotatEle.ChildNodes) { if (!ele.NamespaceURI.Equals(Constants.V4NSData)) { isStructuredValue = false; break; } } } if (!isStructuredValue) { continue; } bool hasType = annotatEle.Attributes["type", Constants.NSMetadata] != null; if (hasType == false) { passed = false; break; } } info = new ExtensionRuleViolationInfo(passed == true ? null : this.ErrorMessage, context.Destination, context.ResponsePayload); return(passed); }
/// <summary> /// Verify Common.Core.4633 /// </summary> /// <param name="context">Service context</param> /// <param name="info">out paramater to return violation information when rule fail</param> /// <returns>true if rule passes; false otherwise</returns> public override bool?Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool?passed = null; // Single primitive individual property is not allowed to have instance annotation. if (VerificationHelper.IsIndividualPropertySinglePrimitiveType(context.ResponsePayload, context.PayloadType)) { info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); return(null); } XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(context.ResponsePayload); XmlElement root = xmlDoc.DocumentElement; string type = string.Empty; if (root.LocalName.Equals("value") && root.NamespaceURI.Equals(Constants.NSMetadata)) { if (root.Attributes["type", Constants.NSMetadata] != null) { type = root.Attributes["type", Constants.NSMetadata].Value; if (type.Contains("Collection(")) { type = type.Substring(type.IndexOf('(') + 1, type.Length - 12); } type = type.Substring(type.LastIndexOf('.') + 1); List <string> complexTypeNames = MetadataHelper.GetAllComplexNameFromMetadata(context.MetadataDocument); if (complexTypeNames.Contains(type)) { string annotation = @"//*[local-name()='value']/*[local-name()='annotation']"; XmlNodeList annoations = xmlDoc.SelectNodes(annotation, ODataNamespaceManager.Instance); if (annoations != null && annoations.Count > 0) { foreach (XmlNode anno in annoations) { if (anno.Attributes["target"] == null || anno.Attributes["target"].Value.Contains(type)) { passed = true; } else { passed = false; break; } } } } } } info = new ExtensionRuleViolationInfo(passed == true ? null : this.ErrorMessage, context.Destination, context.ResponsePayload); return(passed); }
public void TestDirectorySetAttributes() { DMLibDataInfo sourceDataInfo = new DMLibDataInfo(string.Empty); for (int i = 0; i < 3; ++i) { FileNode fileNode = new FileNode(DMLibTestBase.FileName + i) { SizeInByte = DMLibTestBase.FileSizeInKB * 1024L }; if (DMLibTestContext.SourceType != DMLibDataType.Local) { fileNode.Metadata = new Dictionary <string, string>(); fileNode.Metadata.Add("foo", "bar"); fileNode.ContentLanguage = SetAttributesTest.TestContentLanguage; } sourceDataInfo.RootNode.AddFileNode(fileNode); } DirectoryTransferContext context = new DirectoryTransferContext() { SetAttributesCallbackAsync = async(destObj) => { dynamic destCloudObj = destObj; destCloudObj.Properties.ContentType = SetAttributesTest.TestContentType; destCloudObj.Metadata.Add("aa", "bb"); } }; var options = new TestExecutionOptions <DMLibDataInfo>(); options.TransferItemModifier = (node, transferItem) => { dynamic transferOptions = DefaultTransferDirectoryOptions; transferOptions.Recursive = true; transferItem.Options = transferOptions; transferItem.TransferContext = context; }; options.IsDirectoryTransfer = true; var result = this.ExecuteTestCase(sourceDataInfo, options); foreach (FileNode fileNode in sourceDataInfo.EnumerateFileNodes()) { fileNode.Metadata.Add("aa", "bb"); } VerificationHelper.VerifyTransferSucceed(result, sourceDataInfo); VerificationHelper.VerifySingleTransferStatus(result, 3, 0, 0, 3 * DMLibTestBase.FileSizeInKB * 1024L); foreach (FileNode destFileNode in result.DataInfo.EnumerateFileNodes()) { Test.Assert(TestContentType.Equals(destFileNode.ContentType), "Verify content type: {0}, expected {1}", destFileNode.ContentType, TestContentType); if (DMLibTestContext.SourceType != DMLibDataType.Local) { Test.Assert(SetAttributesTest.TestContentLanguage.Equals(destFileNode.ContentLanguage), "Verify ContentLanguage: {0}, expected {1}", destFileNode.ContentLanguage, SetAttributesTest.TestContentLanguage); } } }
public void TestDirectoryCheckContentMD5() { long fileSize = 5 * 1024 * 1024; long totalSize = fileSize * 4; string wrongMD5 = "wrongMD5"; string checkWrongMD5File = "checkWrongMD5File"; string checkCorrectMD5File = "checkCorrectMD5File"; string notCheckWrongMD5File = "notCheckWrongMD5File"; string notCheckCorrectMD5File = "notCheckCorrectMD5File"; DMLibDataInfo sourceDataInfo = new DMLibDataInfo(string.Empty); DirNode checkMD5Folder = new DirNode("checkMD5"); DMLibDataHelper.AddOneFileInBytes(checkMD5Folder, checkWrongMD5File, fileSize); DMLibDataHelper.AddOneFileInBytes(checkMD5Folder, checkCorrectMD5File, fileSize); sourceDataInfo.RootNode.AddDirNode(checkMD5Folder); DirNode notCheckMD5Folder = new DirNode("notCheckMD5"); DMLibDataHelper.AddOneFileInBytes(notCheckMD5Folder, notCheckWrongMD5File, fileSize); DMLibDataHelper.AddOneFileInBytes(notCheckMD5Folder, notCheckCorrectMD5File, fileSize); sourceDataInfo.RootNode.AddDirNode(notCheckMD5Folder); FileNode tmpFileNode = checkMD5Folder.GetFileNode(checkWrongMD5File); tmpFileNode.MD5 = wrongMD5; tmpFileNode = notCheckMD5Folder.GetFileNode(notCheckWrongMD5File); tmpFileNode.MD5 = wrongMD5; SourceAdaptor.GenerateData(sourceDataInfo); TransferEventChecker eventChecker = new TransferEventChecker(); TransferContext context = new TransferContext(); eventChecker.Apply(context); bool failureReported = false; context.FileFailed += (sender, args) => { if (args.Exception != null) { failureReported = args.Exception.Message.Contains(checkWrongMD5File); } }; ProgressChecker progressChecker = new ProgressChecker(4, totalSize, 3, 1, 0, totalSize); context.ProgressHandler = progressChecker.GetProgressHandler(); TransferItem checkMD5Item = new TransferItem() { SourceObject = SourceAdaptor.GetTransferObject(sourceDataInfo.RootPath, checkMD5Folder), DestObject = DestAdaptor.GetTransferObject(sourceDataInfo.RootPath, checkMD5Folder), IsDirectoryTransfer = true, SourceType = DMLibTestContext.SourceType, DestType = DMLibTestContext.DestType, IsServiceCopy = DMLibTestContext.IsAsync, TransferContext = context, Options = new DownloadDirectoryOptions() { DisableContentMD5Validation = false, Recursive = true, }, }; TransferItem notCheckMD5Item = new TransferItem() { SourceObject = SourceAdaptor.GetTransferObject(sourceDataInfo.RootPath, notCheckMD5Folder), DestObject = DestAdaptor.GetTransferObject(sourceDataInfo.RootPath, notCheckMD5Folder), IsDirectoryTransfer = true, SourceType = DMLibTestContext.SourceType, DestType = DMLibTestContext.DestType, IsServiceCopy = DMLibTestContext.IsAsync, TransferContext = context, Options = new DownloadDirectoryOptions() { DisableContentMD5Validation = true, Recursive = true, }, }; var testResult = this.RunTransferItems(new List <TransferItem>() { checkMD5Item, notCheckMD5Item }, new TestExecutionOptions <DMLibDataInfo>()); DMLibDataInfo expectedDataInfo = sourceDataInfo.Clone(); expectedDataInfo.RootNode.GetDirNode(checkMD5Folder.Name).DeleteFileNode(checkWrongMD5File); expectedDataInfo.RootNode.GetDirNode(notCheckMD5Folder.Name).DeleteFileNode(notCheckWrongMD5File); DMLibDataInfo actualDataInfo = testResult.DataInfo; actualDataInfo.RootNode.GetDirNode(checkMD5Folder.Name).DeleteFileNode(checkWrongMD5File); actualDataInfo.RootNode.GetDirNode(notCheckMD5Folder.Name).DeleteFileNode(notCheckWrongMD5File); Test.Assert(DMLibDataHelper.Equals(expectedDataInfo, actualDataInfo), "Verify transfer result."); Test.Assert(failureReported, "Verify md5 check failure is reported."); VerificationHelper.VerifyFinalProgress(progressChecker, 3, 0, 1); if (testResult.Exceptions.Count != 1) { Test.Error("Expect one exception but actually no exception is thrown."); } else { VerificationHelper.VerifyTransferException(testResult.Exceptions[0], TransferErrorCode.SubTransferFails, "1 sub transfer(s) failed."); } }
private void TestSASTokenOfEachVersion(string targetSASVersion, bool isDirectoryTransfer) { Test.Info("Testing version of {0}", targetSASVersion); DMLibDataInfo sourceDataInfo = new DMLibDataInfo(string.Empty); DMLibDataHelper.AddOneFileInBytes(sourceDataInfo.RootNode, DMLibTestBase.FileName, 1024); var options = new TestExecutionOptions <DMLibDataInfo>(); options.IsDirectoryTransfer = isDirectoryTransfer; options.TransferItemModifier = (fileNode, transferItem) => { dynamic transferOptions = isDirectoryTransfer ? DefaultTransferDirectoryOptions : DefaultTransferOptions; transferItem.Options = transferOptions; if (isDirectoryTransfer) { transferItem.TransferContext = new DirectoryTransferContext(); transferItem.TransferContext.FileFailed += (source, e) => { Test.Error(e.Exception.ToString()); }; DirectoryOptions dirOptions = transferItem.Options as DirectoryOptions; dirOptions.Recursive = true; } else { transferItem.TransferContext = new SingleTransferContext(); } transferItem.TransferContext.ShouldOverwriteCallbackAsync = TransferContext.ForceOverwrite; }; string sourceSAS = null; string destSAS = null; switch (DMLibTestContext.SourceType) { case DMLibDataType.CloudBlob: case DMLibDataType.AppendBlob: case DMLibDataType.BlockBlob: case DMLibDataType.PageBlob: if ((DMLibTestContext.SourceType == DMLibDataType.AppendBlob) && (string.CompareOrdinal(targetSASVersion, "2015-04-05") < 0)) { break; } SourceAdaptor.CreateIfNotExists(); CloudBlobDataAdaptor blobAdaptor = SourceAdaptor as CloudBlobDataAdaptor; sourceSAS = Util.SASGenerator.GetSharedAccessSignature(blobAdaptor.GetBaseContainer(), new SharedAccessBlobPolicy { Permissions = isDirectoryTransfer ? SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.List : SharedAccessBlobPermissions.Read, SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddHours(1) }, null, null, null, targetSASVersion); break; case DMLibDataType.CloudFile: if (string.CompareOrdinal(targetSASVersion, "2015-02-21") < 0) { break; } SourceAdaptor.CreateIfNotExists(); CloudFileDataAdaptor fileAdaptor = SourceAdaptor as CloudFileDataAdaptor; sourceSAS = Util.SASGenerator.GetSharedAccessSignature( fileAdaptor.GetBaseShare(), new SharedAccessFilePolicy { Permissions = isDirectoryTransfer ? SharedAccessFilePermissions.List | SharedAccessFilePermissions.Read : SharedAccessFilePermissions.Read, SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddHours(1) }, null, null, null, targetSASVersion); break; default: break; } if ((DMLibTestContext.CopyMethod != DMLibCopyMethod.ServiceSideAsyncCopy) || (string.CompareOrdinal(targetSASVersion, "2014-02-14") >= 0)) { switch (DMLibTestContext.DestType) { case DMLibDataType.CloudBlob: case DMLibDataType.AppendBlob: case DMLibDataType.BlockBlob: case DMLibDataType.PageBlob: if ((DMLibTestContext.DestType == DMLibDataType.AppendBlob) && (string.CompareOrdinal(targetSASVersion, "2015-04-05") < 0)) { break; } DestAdaptor.CreateIfNotExists(); CloudBlobDataAdaptor blobAdaptor = DestAdaptor as CloudBlobDataAdaptor; destSAS = Util.SASGenerator.GetSharedAccessSignature(blobAdaptor.GetBaseContainer(), new SharedAccessBlobPolicy { Permissions = (DMLibTestContext.CopyMethod == DMLibCopyMethod.ServiceSideAsyncCopy) ? SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read : SharedAccessBlobPermissions.Write, SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddHours(1) }, null, null, null, targetSASVersion); break; case DMLibDataType.CloudFile: if (string.CompareOrdinal(targetSASVersion, "2015-02-21") < 0) { break; } DestAdaptor.CreateIfNotExists(); CloudFileDataAdaptor fileAdaptor = DestAdaptor as CloudFileDataAdaptor; destSAS = Util.SASGenerator.GetSharedAccessSignature( fileAdaptor.GetBaseShare(), new SharedAccessFilePolicy { Permissions = (DMLibTestContext.CopyMethod == DMLibCopyMethod.ServiceSideAsyncCopy) ? SharedAccessFilePermissions.Write | SharedAccessFilePermissions.Read : SharedAccessFilePermissions.Write, SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddHours(1) }, null, null, null, targetSASVersion); break; default: break; } } if (null != sourceSAS) { options.SourceCredentials = new StorageCredentials(sourceSAS); } if (null != destSAS) { options.DestCredentials = new StorageCredentials(destSAS); } var result = this.ExecuteTestCase(sourceDataInfo, options); VerificationHelper.VerifyTransferSucceed(result, sourceDataInfo); }
public void DirectoryShouldTransfer() { // Prepare data int totaFileNumber = DMLibTestConstants.FlatFileCount; int expectedTransferred = totaFileNumber, transferred = 0; int expectedSkipped = 0, skipped = 0; int expectedFailed = 0, failed = 0; DMLibDataInfo sourceDataInfo = this.GenerateSourceDataInfo(FileNumOption.FlatFolder, 1024); DirectoryTransferContext dirTransferContext = new DirectoryTransferContext(); List <String> notTransferredFileNames = new List <String>(); dirTransferContext.ShouldTransferCallbackAsync = async(source, dest) => { if (Helper.RandomBoolean()) { return(true); } else { Interlocked.Decrement(ref expectedTransferred); string fullName = DMLibTestHelper.TransferInstanceToString(source); string fileName = fullName.Substring(fullName.IndexOf(DMLibTestBase.FileName)); lock (notTransferredFileNames) { notTransferredFileNames.Add(fileName); } Test.Info("{0} is filterred in ShouldTransfer.", fileName); return(false); } }; dirTransferContext.FileTransferred += (object sender, TransferEventArgs args) => { Interlocked.Increment(ref transferred); }; dirTransferContext.FileSkipped += (object sender, TransferEventArgs args) => { Interlocked.Increment(ref skipped); }; dirTransferContext.FileFailed += (object sender, TransferEventArgs args) => { Interlocked.Increment(ref failed); }; var options = new TestExecutionOptions <DMLibDataInfo>(); options.IsDirectoryTransfer = true; options.TransferItemModifier = (fileNode, transferItem) => { transferItem.TransferContext = dirTransferContext; dynamic transferOptions = DefaultTransferDirectoryOptions; transferOptions.Recursive = true; transferItem.Options = transferOptions; }; // Execute test case var result = this.ExecuteTestCase(sourceDataInfo, options); // Verify result DMLibDataInfo expectedDataInfo = sourceDataInfo.Clone(); DirNode expectedRootNode = expectedDataInfo.RootNode; foreach (string fileNames in notTransferredFileNames) { expectedRootNode.DeleteFileNode(fileNames); } VerificationHelper.VerifyTransferSucceed(result, expectedDataInfo); Test.Assert(expectedTransferred == transferred, string.Format("Verify transferred number. Expected: {0}, Actual: {1}", expectedTransferred, transferred)); Test.Assert(expectedSkipped == skipped, string.Format("Verify skipped number. Expected: {0}, Actual: {1}", expectedSkipped, skipped)); Test.Assert(expectedFailed == failed, string.Format("Verify failed number. Expected: {0}, Actual: {1}", expectedFailed, failed)); }
/// <summary> /// Verify Common.Core.4626 /// </summary> /// <param name="context">Service context</param> /// <param name="info">out parameter to return violation information when rule fail</param> /// <returns>true if rule passes; false otherwise</returns> public override bool?Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool?passed = null; info = null; // Single primitive individual property is not allowed to have instance annotation. if (VerificationHelper.IsIndividualPropertySinglePrimitiveType(context.ResponsePayload, context.PayloadType)) { return(null); } XmlDocument xmlDoc = new XmlDocument(); // Test Data // Url:http://services.odata.org/V4/OData/OData.svc/Products(0)/Description?$format=xml or http://services.odata.org/V4/OData/OData.svc/Persons(0)?$format=atom // xmlDoc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><m:value m:context=\"http://services.odata.org/V4/OData/OData.svc/$metadata#Products(0)/Description\" xmlns:atom=\"http://www.w3.org/2005/Atom\" xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" xmlns:georss=\"http://www.georss.org/georss\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\">Whole grain bread <m:annotation term=\"com.contoso.PersonalInfo.PhoneNumbers\" m:type=\"Collection(String)\"><m:element>(203)555-1718</m:element><m:element>(203)555-1719</m:element></m:annotation></m:value>"); xmlDoc.LoadXml(context.ResponsePayload); XmlNodeList annotationElements = xmlDoc.SelectNodes(@"//*[local-name()='annotation']", ODataNamespaceManager.Instance); foreach (XmlNode annotatEle in annotationElements) { bool isCollectionValued = false; foreach (XmlNode ele in annotatEle.ChildNodes) { if (ele.Name.Equals("element")) { isCollectionValued = true; } else { isCollectionValued = false; break; } } if (isCollectionValued) { if (annotatEle.Attributes["type", Constants.NSMetadata] != null) { string typeName = annotatEle.Attributes["type", Constants.NSMetadata].Value; if (typeName.Contains("Collection(") && typeName.Remove(0, typeName.Length - 1).Equals(")")) { passed = true; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); break; } } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); break; } } } return(passed); }
private void TestAccessCondition(SourceOrDest sourceOrDest) { string eTag = "notmatch"; AccessCondition accessCondition = new AccessCondition() { IfMatchETag = eTag }; DMLibDataInfo sourceDataInfo = new DMLibDataInfo(string.Empty); DMLibDataHelper.AddOneFileInBytes(sourceDataInfo.RootNode, DMLibTestBase.FileName, 1024); DMLibDataInfo destDataInfo = new DMLibDataInfo(string.Empty); DMLibDataHelper.AddOneFileInBytes(destDataInfo.RootNode, DMLibTestBase.FileName, 1024); var options = new TestExecutionOptions <DMLibDataInfo>(); if (sourceOrDest == SourceOrDest.Dest) { options.DestTransferDataInfo = destDataInfo; } options.TransferItemModifier = (fileNode, transferItem) => { dynamic transferOptions = DefaultTransferOptions; if (sourceOrDest == SourceOrDest.Source) { transferOptions.SourceAccessCondition = accessCondition; } else { transferOptions.DestinationAccessCondition = accessCondition; } transferItem.Options = transferOptions; }; var result = this.ExecuteTestCase(sourceDataInfo, options); if (sourceOrDest == SourceOrDest.Dest) { Test.Assert(DMLibDataHelper.Equals(destDataInfo, result.DataInfo), "Verify no file is transferred."); } else { if (DMLibTestContext.DestType != DMLibDataType.Stream) { Test.Assert(DMLibDataHelper.Equals(new DMLibDataInfo(string.Empty), result.DataInfo), "Verify no file is transferred."); } else { foreach (var fileNode in result.DataInfo.EnumerateFileNodes()) { Test.Assert(fileNode.SizeInByte == 0, "Verify file {0} is empty", fileNode.Name); } } } // Verify TransferException if (result.Exceptions.Count != 1) { Test.Error("There should be exactly one exceptions."); return; } Exception exception = result.Exceptions[0]; #if DNXCORE50 VerificationHelper.VerifyTransferException(exception, TransferErrorCode.Unknown); // TODO: The InnerException is as expected but has a different message and HttpStatusCode // compared to the desktop version of XSCL; is this an XSCL bug? VerificationHelper.VerifyStorageException(exception.InnerException, 0, "The format of value 'notmatch' is invalid."); #else VerificationHelper.VerifyTransferException(exception, TransferErrorCode.Unknown); // Verify innner StorageException VerificationHelper.VerifyStorageException(exception.InnerException, (int)HttpStatusCode.PreconditionFailed, "The condition specified using HTTP conditional header(s) is not met."); #endif }
private void TestDirectoryCheckContentMD5StreamResume(bool checkMD5) { long fileSize = 5 * 1024; int fileCountMulti = 32; long totalSize = fileSize * 4 * fileCountMulti; string wrongMD5 = "wrongMD5"; string wrongMD5File = "wrongMD5File"; string correctMD5File = "correctMD5File"; // Prepare data for transfer items with checkMD5 DMLibDataInfo sourceDataInfo = new DMLibDataInfo(string.Empty); DirNode checkMD5Folder = new DirNode(checkMD5 ? "checkMD5" : "notCheckMD5"); for (int i = 0; i < fileCountMulti; ++i) { var wrongMD5FileNode = new FileNode($"{wrongMD5File}_{i}") { SizeInByte = fileSize, MD5 = wrongMD5 }; checkMD5Folder.AddFileNode(wrongMD5FileNode); DMLibDataHelper.AddOneFileInBytes(checkMD5Folder, $"{correctMD5File}_{i}", fileSize); } sourceDataInfo.RootNode.AddDirNode(checkMD5Folder); SourceAdaptor.GenerateData(sourceDataInfo); DestAdaptor.Cleanup(); TransferEventChecker eventChecker = new TransferEventChecker(); CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); using (var resumeStream = new MemoryStream()) { TransferContext context = new DirectoryTransferContext(resumeStream); eventChecker.Apply(context); ProgressChecker progressChecker = new ProgressChecker(2 * fileCountMulti, totalSize, checkMD5 ? fileCountMulti : 2 * fileCountMulti, null, 0, totalSize); context.ProgressHandler = progressChecker.GetProgressHandler(); List <Exception> transferExceptions = new List <Exception>(); TransferItem checkMD5Item = new TransferItem() { SourceObject = SourceAdaptor.GetTransferObject(sourceDataInfo.RootPath, checkMD5Folder), DestObject = DestAdaptor.GetTransferObject(sourceDataInfo.RootPath, checkMD5Folder), IsDirectoryTransfer = true, SourceType = DMLibTestContext.SourceType, DestType = DMLibTestContext.DestType, IsServiceCopy = DMLibTestContext.IsAsync, TransferContext = context, Options = new DownloadDirectoryOptions() { DisableContentMD5Validation = !checkMD5, Recursive = true, }, CancellationToken = cancellationTokenSource.Token, }; var executionOption = new TestExecutionOptions <DMLibDataInfo>(); executionOption.AfterAllItemAdded = () => { // Wait until there are data transferred if (!progressChecker.DataTransferred.WaitOne(30000)) { Test.Error("No progress in 30s."); } // Cancel the transfer and store the second checkpoint cancellationTokenSource.Cancel(); }; executionOption.LimitSpeed = true; var testResult = this.RunTransferItems(new List <TransferItem>() { checkMD5Item }, executionOption); if (null != testResult.Exceptions) { foreach (var exception in testResult.Exceptions) { Test.Info("Got exception during transferring. {0}", exception); } } eventChecker = new TransferEventChecker(); resumeStream.Position = 0; context = new DirectoryTransferContext(resumeStream); eventChecker.Apply(context); bool failureReported = false; context.FileFailed += (sender, args) => { if (args.Exception != null) { failureReported = args.Exception.Message.Contains(wrongMD5File); } transferExceptions.Add(args.Exception); }; progressChecker.Reset(); context.ProgressHandler = progressChecker.GetProgressHandler(); checkMD5Item = checkMD5Item.Clone(); checkMD5Item.TransferContext = context; testResult = this.RunTransferItems(new List <TransferItem>() { checkMD5Item }, new TestExecutionOptions <DMLibDataInfo>()); DMLibDataInfo expectedDataInfo = sourceDataInfo.Clone(); DMLibDataInfo actualDataInfo = testResult.DataInfo; for (int i = 0; i < fileCountMulti; ++i) { expectedDataInfo.RootNode.GetDirNode(checkMD5Folder.Name).DeleteFileNode($"{wrongMD5File}_{i}"); actualDataInfo.RootNode.GetDirNode(checkMD5Folder.Name).DeleteFileNode($"{wrongMD5File}_{i}"); } Test.Assert(DMLibDataHelper.Equals(expectedDataInfo, actualDataInfo), "Verify transfer result."); Test.Assert(checkMD5 ? failureReported : !failureReported, "Verify md5 check failure is expected."); VerificationHelper.VerifyFinalProgress(progressChecker, checkMD5 ? fileCountMulti : 2 * fileCountMulti, 0, checkMD5 ? fileCountMulti : 0); if (checkMD5) { if (testResult.Exceptions.Count != 0 || transferExceptions.Count != fileCountMulti) { Test.Error("Expect one exception but actually no exception is thrown."); } else { for (int i = 0; i < fileCountMulti; ++i) { VerificationHelper.VerifyExceptionErrorMessage(transferExceptions[i], new string[] { "The MD5 hash calculated from the downloaded data does not match the MD5 hash stored in the property of source" }); } } } else { Test.Assert(testResult.Exceptions.Count == 0, "Should no exception thrown out when disabling check md5"); } } }