Beispiel #1
0
        public void TestResume()
        {
            int           fileSizeInKB   = 100 * 1024;
            DMLibDataInfo sourceDataInfo = new DMLibDataInfo(string.Empty);

            DMLibDataHelper.AddOneFile(sourceDataInfo.RootNode, DMLibTestBase.FileName, fileSizeInKB);

            CancellationTokenSource tokenSource = new CancellationTokenSource();

            TransferItem transferItem = null;
            var          options      = new TestExecutionOptions <DMLibDataInfo>();

            options.LimitSpeed = true;

            bool IsStreamJournal = random.Next(0, 2) == 0;

            using (Stream journalStream = new MemoryStream())
            {
                TransferContext transferContext = IsStreamJournal ? new SingleTransferContext(journalStream) : new SingleTransferContext();
                var             progressChecker = new ProgressChecker(1, fileSizeInKB * 1024, 0, 1, 0, fileSizeInKB * 1024);
                transferContext.ProgressHandler = progressChecker.GetProgressHandler();
                options.TransferItemModifier    = (fileName, item) =>
                {
                    dynamic transferOptions = DefaultTransferOptions;

                    if (DMLibTestContext.SourceType == DMLibDataType.CloudFile &&
                        DMLibTestContext.DestType == DMLibDataType.CloudFile)
                    {
                        transferOptions.PreserveSMBAttributes  = true;
                        transferOptions.PreserveSMBPermissions = true;
                    }

                    item.CancellationToken    = tokenSource.Token;
                    item.TransferContext      = transferContext;
                    transferItem              = item;
                    item.DisableStreamDispose = true;
                    item.Options              = transferOptions;
                };

                TransferCheckpoint firstCheckpoint = null, secondCheckpoint = null;
                options.AfterAllItemAdded = () =>
                {
                    if (IsStreamJournal &&
                        (DMLibTestContext.SourceType == DMLibDataType.Stream ||
                         DMLibTestContext.DestType == DMLibDataType.Stream))
                    {
                        return;
                    }

                    // Wait until there are data transferred
                    progressChecker.DataTransferred.WaitOne();

                    // Store the first checkpoint
                    if (!IsStreamJournal)
                    {
                        firstCheckpoint = transferContext.LastCheckpoint;
                    }
                    Thread.Sleep(1000);

                    // Cancel the transfer and store the second checkpoint
                    tokenSource.Cancel();
                };

                if ((DMLibTestContext.SourceType == DMLibDataType.Stream) || (DMLibTestContext.DestType == DMLibDataType.Stream))
                {
                    options.DisableDestinationFetch = true;
                }

                // Cancel and store checkpoint for resume
                var result = this.ExecuteTestCase(sourceDataInfo, options);

                if (!IsStreamJournal)
                {
                    secondCheckpoint = transferContext.LastCheckpoint;
                }
                else
                {
                    if (DMLibTestContext.SourceType == DMLibDataType.Stream || DMLibTestContext.DestType == DMLibDataType.Stream)
                    {
                        Test.Assert(result.Exceptions.Count == 1, "Verify job is failed");
                        Exception jobException = result.Exceptions[0];
                        Test.Info("{0}", jobException);
                        VerificationHelper.VerifyExceptionErrorMessage(jobException, "Cannot deserialize to TransferLocation when its TransferLocationType is Stream.");
                        transferItem.DisableStreamDispose = false;
                        transferItem.CloseStreamIfNecessary();
                        return;
                    }
                }

                Test.Assert(result.Exceptions.Count == 1, "Verify job is cancelled");
                Exception exception = result.Exceptions[0];
                Helper.VerifyCancelException(exception);

                TransferCheckpoint firstResumeCheckpoint = null, secondResumeCheckpoint = null;
                ProgressChecker    firstProgressChecker = null, secondProgressChecker = null;

                if (!IsStreamJournal)
                {
                    // DMLib doesn't support to resume transfer from a checkpoint which is inconsistent with
                    // the actual transfer progress when the destination is an append blob.
                    if (Helper.RandomBoolean() && (DMLibTestContext.DestType != DMLibDataType.AppendBlob || (DMLibTestContext.CopyMethod == DMLibCopyMethod.ServiceSideAsyncCopy)))
                    {
                        Test.Info("Resume with the first checkpoint first.");
                        firstResumeCheckpoint  = firstCheckpoint;
                        secondResumeCheckpoint = secondCheckpoint;
                    }
                    else
                    {
                        Test.Info("Resume with the second checkpoint first.");
                        firstResumeCheckpoint  = secondCheckpoint;
                        secondResumeCheckpoint = firstCheckpoint;
                    }
                }

                // first progress checker
                if (DMLibTestContext.SourceType == DMLibDataType.Stream && DMLibTestContext.DestType != DMLibDataType.BlockBlob)
                {
                    // The destination is already created, will cause a transfer skip
                    firstProgressChecker = new ProgressChecker(2, fileSizeInKB * 1024, 0, 1 /* failed */, 1 /* skipped */, fileSizeInKB * 1024);
                }
                else if (DMLibTestContext.DestType == DMLibDataType.Stream || (DMLibTestContext.SourceType == DMLibDataType.Stream && DMLibTestContext.DestType == DMLibDataType.BlockBlob))
                {
                    firstProgressChecker = new ProgressChecker(2, 2 * fileSizeInKB * 1024, 1 /* transferred */, 1 /* failed */, 0, 2 * fileSizeInKB * 1024);
                }
                else
                {
                    firstProgressChecker = new ProgressChecker(1, fileSizeInKB * 1024, 1, 0, 0, fileSizeInKB * 1024);
                }

                // second progress checker
                if (DMLibTestContext.SourceType == DMLibDataType.Stream)
                {
                    // The destination is already created, will cause a transfer skip
                    secondProgressChecker = new ProgressChecker(2, fileSizeInKB * 1024, 0, 1 /* failed */, 1 /* skipped */, fileSizeInKB * 1024);
                }
                else if (DMLibTestContext.DestType == DMLibDataType.Stream)
                {
                    secondProgressChecker = new ProgressChecker(2, 2 * fileSizeInKB * 1024, 1 /* transferred */, 1 /* failed */, 0, 2 * fileSizeInKB * 1024);
                }
                else if (DMLibTestContext.DestType == DMLibDataType.AppendBlob && (DMLibTestContext.CopyMethod != DMLibCopyMethod.ServiceSideAsyncCopy))
                {
                    secondProgressChecker = new ProgressChecker(1, fileSizeInKB * 1024, 0, 1 /* failed */, 0, fileSizeInKB * 1024);
                }
                else
                {
                    secondProgressChecker = new ProgressChecker(1, fileSizeInKB * 1024, 1 /* transferred */, 0, 0, fileSizeInKB * 1024);
                }

                // resume with firstResumeCheckpoint
                TransferItem    resumeItem = transferItem.Clone();
                TransferContext resumeContext = null;

                if (IsStreamJournal)
                {
                    Exception deserializeEX = null;
                    try
                    {
                        resumeContext = new SingleTransferContext(journalStream)
                        {
                            ProgressHandler = firstProgressChecker.GetProgressHandler()
                        };
                    }
                    catch (Exception ex)
                    {
                        if ((DMLibTestContext.SourceType != DMLibDataType.Stream) &&
                            (DMLibTestContext.DestType != DMLibDataType.Stream))
                        {
                            Test.Error("Should no exception in deserialization when no target is stream.");
                        }

                        deserializeEX = ex;
                    }
                }
                else
                {
                    resumeContext = new SingleTransferContext(IsStreamDirection() ? firstResumeCheckpoint : DMLibTestHelper.RandomReloadCheckpoint(firstResumeCheckpoint))
                    {
                        ProgressHandler = firstProgressChecker.GetProgressHandler()
                    };
                }

                resumeItem.TransferContext = resumeContext;

                result = this.RunTransferItems(new List <TransferItem>()
                {
                    resumeItem
                }, new TestExecutionOptions <DMLibDataInfo>());

                if (DMLibTestContext.SourceType == DMLibDataType.Stream || DMLibTestContext.DestType == DMLibDataType.Stream)
                {
                    Test.Assert(result.Exceptions.Count == 1, "Verify error reported when source/destination is stream.");
                    exception = result.Exceptions[0];
                    VerificationHelper.VerifyExceptionErrorMessage(result.Exceptions[0], "Resuming transfer from or to a stream is not supported");
                }
                else
                {
                    // For sync copy, recalculate md5 of destination by downloading the file to local.
                    if (IsCloudService(DMLibTestContext.DestType) && (DMLibTestContext.CopyMethod != DMLibCopyMethod.ServiceSideAsyncCopy))
                    {
                        DMLibDataHelper.SetCalculatedFileMD5(result.DataInfo, DestAdaptor);
                    }

                    VerificationHelper.VerifySingleObjectResumeResult(result, sourceDataInfo);
                }

                if (!IsStreamJournal)
                {
                    // resume with secondResumeCheckpoint
                    resumeItem    = transferItem.Clone();
                    resumeContext = new SingleTransferContext(
                        IsStreamDirection() ? secondResumeCheckpoint : DMLibTestHelper.RandomReloadCheckpoint(secondResumeCheckpoint))
                    {
                        ProgressHandler = secondProgressChecker.GetProgressHandler()
                    };
                    resumeItem.TransferContext = resumeContext;

                    result = this.RunTransferItems(new List <TransferItem>()
                    {
                        resumeItem
                    }, new TestExecutionOptions <DMLibDataInfo>());

                    if (DMLibTestContext.SourceType == DMLibDataType.Stream || DMLibTestContext.DestType == DMLibDataType.Stream)
                    {
                        Test.Assert(result.Exceptions.Count == 1, "Verify error reported when source/destination is stream.");
                        exception = result.Exceptions[0];
                        VerificationHelper.VerifyExceptionErrorMessage(result.Exceptions[0], "Resuming transfer from or to a stream is not supported");
                    }
                    else if (DMLibTestContext.DestType == DMLibDataType.AppendBlob && (DMLibTestContext.CopyMethod != DMLibCopyMethod.ServiceSideAsyncCopy))
                    {
                        Test.Assert(result.Exceptions.Count == 1, "Verify reumse fails when checkpoint is inconsistent with the actual progress when destination is append blob.");
                        exception = result.Exceptions[0];
                        Test.Assert(exception is InvalidOperationException, "Verify reumse fails when checkpoint is inconsistent with the actual progress when destination is append blob.");
                        VerificationHelper.VerifyExceptionErrorMessage(exception, "Destination might be changed by other process or application.");
                    }
                    else
                    {
                        // For sync copy, recalculate md5 of destination by downloading the file to local.
                        if (IsCloudService(DMLibTestContext.DestType) && (DMLibTestContext.CopyMethod != DMLibCopyMethod.ServiceSideAsyncCopy))
                        {
                            DMLibDataHelper.SetCalculatedFileMD5(result.DataInfo, DestAdaptor);
                        }

                        VerificationHelper.VerifySingleObjectResumeResult(result, sourceDataInfo);
                    }
                }

                if (DMLibTestContext.SourceType == DMLibDataType.CloudFile &&
                    DMLibTestContext.DestType == DMLibDataType.CloudFile)
                {
                    Helper.CompareSMBProperties(sourceDataInfo.RootNode, result.DataInfo.RootNode, true);
                    Helper.CompareSMBPermissions(
                        sourceDataInfo.RootNode,
                        result.DataInfo.RootNode,
                        PreserveSMBPermissions.Owner | PreserveSMBPermissions.Group | PreserveSMBPermissions.DACL | PreserveSMBPermissions.SACL);
                }
            }
        }
        public TestResult <DMLibDataInfo> RunTransferItems(List <TransferItem> items, TestExecutionOptions <DMLibDataInfo> options)
        {
            Dictionary <TransferItem, Task <TransferStatus> > allTasks = new Dictionary <TransferItem, Task <TransferStatus> >();
            var testResult = new TestResult <DMLibDataInfo>();

            testResult.TransferItems = items;

            try
            {
                foreach (TransferItem item in items)
                {
                    DMLibWrapper wrapper = GetDMLibWrapper(item.SourceType, item.DestType, DMLibTestContext.IsAsync);

                    if (item.BeforeStarted != null)
                    {
                        item.BeforeStarted();
                    }

                    try
                    {
                        if (options.LimitSpeed)
                        {
                            OperationContext.GlobalSendingRequest            += this.LimitSpeed;
                            TransferManager.Configurations.ParallelOperations = DMLibTestConstants.LimitedSpeedNC;
                        }

                        if (options.BlockSize.HasValue)
                        {
                            TransferManager.Configurations.BlockSize = options.BlockSize.Value;
                        }

                        allTasks.Add(item, wrapper.DoTransfer(item));
                    }
                    catch (Exception e)
                    {
                        testResult.AddException(e);
                    }

                    if (item.AfterStarted != null)
                    {
                        item.AfterStarted();
                    }
                }

                if (options.AfterAllItemAdded != null)
                {
                    options.AfterAllItemAdded();
                }

                try
                {
                    Task.WaitAll(allTasks.Values.ToArray(), options.TimeoutInMs);
                }
                catch (Exception e)
                {
                    AggregateException ae = e as AggregateException;
                    if (ae != null)
                    {
                        ae = ae.Flatten();
                        foreach (var innerE in ae.InnerExceptions)
                        {
                            testResult.AddException(innerE);
                        }
                    }
                    else
                    {
                        testResult.AddException(e);
                    }
                }
            }
            finally
            {
                if (options.LimitSpeed)
                {
                    OperationContext.GlobalSendingRequest            -= this.LimitSpeed;
                    TransferManager.Configurations.ParallelOperations = DMLibTestConstants.DefaultNC;
                }
                TransferManager.Configurations.BlockSize = DMLibTestConstants.DefaultBlockSize;
            }

            Parallel.ForEach(allTasks, pair =>
            {
                TransferItem transferItem  = pair.Key;
                Task <TransferStatus> task = pair.Value;

                transferItem.CloseStreamIfNecessary();

                try
                {
                    transferItem.FinalStatus = task.Result;
                }
                catch (Exception e)
                {
                    transferItem.Exception = e;
                }
            });

            if (!options.DisableDestinationFetch)
            {
                testResult.DataInfo = DestAdaptor.GetTransferDataInfo(string.Empty);
            }

            foreach (var exception in testResult.Exceptions)
            {
                Test.Info("Exception from DMLib: {0}", exception.ToString());
            }

            return(testResult);
        }