Exemple #1
0
                    public void ShouldPassThroughAllProvidedIntermediatesInOrder()
                    {
                        // Arrange
                        using var arena = new TestArena();
                        var resumeStrategy = Substitute.For <IResumeStrategy>();

                        resumeStrategy.CanResume(
                            Arg.Any <IFileResource>(),
                            Arg.Any <IFileResource>(),
                            Arg.Any <Stream>(),
                            Arg.Any <Stream>())
                        .Returns(false);
                        var(source, target) = (arena.SourceFileSystem, arena.TargetFileSystem);
                        var relPath = GetRandomString();
                        var allData = GetRandomBytes(100, 200); // small buffer, likely to be read in one pass

                        arena.CreateResource(
                            arena.SourcePath,
                            relPath,
                            allData);
                        var intermediateCalls = new List <string>();
                        var endCalls          = new List <string>();
                        var intermediate1     = new GenericPassThrough(
                            (data, count) => intermediateCalls.Add("first"),
                            () => endCalls.Add("first")
                            );
                        var intermediate2 = new GenericPassThrough(
                            (data, count) => intermediateCalls.Add("second"),
                            () => endCalls.Add("second")
                            );
                        var intermediate3 = new GenericPassThrough(
                            (data, count) => intermediateCalls.Add("third"),
                            () => endCalls.Add("third")
                            );
                        var expected = new[]
                        {
                            "first",
                            "second",
                            "third"
                        };
                        var sut = Create(
                            resumeStrategy,
                            new IPassThrough[]
                        {
                            intermediate1, intermediate2, intermediate3
                        },
                            // this test is about notifiers, so we'll
                            // just pretend that all sources are to be required
                            // at the target
                            filters: CreatePermissiveFilter());

                        // Act
                        sut.Synchronize(source, target);
                        // Assert
                        Expect(intermediateCalls)
                        .To.Equal(expected);
                        Expect(endCalls)
                        .To.Equal(expected);
                    }
Exemple #2
0
                    public void ShouldResumeWhenResumeStrategySaysYes()
                    {
                        // Arrange
                        using var arena = new TestArena();
                        var resumeStrategy = Substitute.For <IResumeStrategy>();

                        resumeStrategy.CanResume(
                            Arg.Any <IFileResource>(),
                            Arg.Any <IFileResource>(),
                            Arg.Any <Stream>(),
                            Arg.Any <Stream>()
                            )
                        .Returns(true);
                        var(source, target) = (arena.SourceFileSystem, arena.TargetFileSystem);
                        var relPath     = GetRandomString();
                        var allData     = GetRandomBytes(1024);
                        var partialSize = GetRandomInt(384, 768);
                        var partialData = allData.Take(partialSize)
                                          .ToArray();
                        var expected = allData.Skip(partialSize)
                                       .ToArray();
                        var targetFilePath = arena.CreateResource(
                            arena.TargetPath,
                            relPath,
                            partialData);

                        arena.CreateResource(
                            arena.SourcePath,
                            relPath,
                            allData);
                        var captured     = new List <byte>();
                        var ended        = false;
                        var intermediate = new GenericPassThrough(
                            (data, count) => captured.AddRange(data.Take(count)),
                            () => ended = true
                            );
                        var sut = Create(
                            resumeStrategy,
                            new IPassThrough[] { intermediate }
                            );

                        // Act
                        sut.Synchronize(source, target);
                        // Assert
                        var targetData = File.ReadAllBytes(targetFilePath);

                        Expect(targetData)
                        .To.Equal(allData);
                        var transferred = captured.ToArray();

                        Expect(transferred)
                        .To.Equal(expected, "unexpected transferred data");
                        Expect(ended)
                        .To.Be.True();
                    }
Exemple #3
0
            public void ShouldRetryOnError()
            {
                // Arrange
                using var arena = new TestArena();
                var options     = Substitute.For <IOptions>();

                options.Retries.Returns(3);

                using var resetter = new AutoResetter <int>(() =>
                {
                    var original           = StreamSource.MaxBuffer;
                    StreamSource.MaxBuffer = 1;
                    return(original);
                },
                                                            original => StreamSource.MaxBuffer = original);
                var haveErrored      = false;
                var errorPassThrough = new GenericPassThrough(
                    (data, size) =>
                {
                    if (!haveErrored)
                    {
                        haveErrored = true;
                        throw new DirectoryNotFoundException("foo");
                    }
                },
                    () =>
                {
                }
                    );
                // keep the size small since we're forcing a flush at every byte
                var sourceFile = arena.CreateSourceFile(data: GetRandomBytes(10, 20));
                var expected   = arena.TargetPathFor(sourceFile);
                var sut        = Create(
                    intermediatePipes: new IPassThrough[] { errorPassThrough },
                    options: options);

                // Act
                sut.Synchronize(arena.SourceFileSystem, arena.TargetFileSystem);
                // Assert
                Expect(expected)
                .To.Exist();
                Expect(File.ReadAllBytes(expected))
                .To.Equal(sourceFile.Data);
            }
Exemple #4
0
            public void ShouldNotifyNotifiablePipesWithPossibleResumeSizes()
            {
                // Arrange
                using var arena = new TestArena();
                var missingData = GetRandomBytes(100);

                arena.CreateSourceResource(
                    "missing",
                    missingData);
                var partialFileAllData = "hello world".AsBytes();
                var partialTargetData  = "hello".AsBytes();

                arena.CreateSourceResource("partial", partialFileAllData);
                arena.CreateTargetResource("partial", partialTargetData);
                var existingData = GetRandomBytes(100);

                arena.CreateSourceResource("existing", existingData);
                arena.CreateTargetResource("existing", existingData);
                var intermediate1 = new GenericPassThrough(
                    (data, count) =>
                {
                },
                    () =>
                {
                });
                var notifiable = new NotifiableGenericPassThrough(
                    (data, count) =>
                {
                },
                    () =>
                {
                });
                var options = Substitute.For <IOptions>();

                options.ResumeCheckBytes.Returns(512);
                var sut = Create(
                    new SimpleResumeStrategy(options, Substitute.For <IMessageWriter>()),
                    new IPassThrough[] { notifiable, intermediate1 }
                    .Randomize()
                    .ToArray()
                    );

                // Act
                sut.Synchronize(
                    arena.SourceFileSystem,
                    arena.TargetFileSystem);
                // Assert
                var partialResultData = arena.TargetFileSystem.ReadAllBytes(
                    "partial");

                Expect(partialResultData)
                .To.Equal(partialFileAllData,
                          () => $@"Expected {
                                partialFileAllData.Length
                            } bytes, but got {
                                partialResultData.Length
                            }: '{
                                partialFileAllData.AsString()
                            }' vs '{
                                partialResultData.AsString()
                            }'");
                Expect(arena.TargetFileSystem.ReadAllBytes("existing"))
                .To.Equal(existingData);
                Expect(arena.TargetFileSystem.ReadAllBytes("missing"))
                .To.Equal(missingData);
                Expect(notifiable.BatchStartedNotifications)
                .To.Contain.Only(1)
                .Item();     // should only have one initial notification
                var initial = notifiable.BatchStartedNotifications.Single();

                Expect(initial.resources)
                .To.Contain
                .Only(2)
                .Items();     // should only have partial and missing in sync queue
                Expect(initial.resources)
                .To.Contain.Exactly(1)
                .Matched.By(
                    resource => resource.RelativePath == "missing"
                    );
                Expect(initial.resources)
                .To.Contain.Exactly(1)
                .Matched.By(
                    resource => resource.RelativePath == "partial"
                    );

                var batchComplete = notifiable.BatchCompletedNotifications.Single();

                Expect(batchComplete.resources)
                .To.Contain
                .Only(2)
                .Items();     // should only have partial and missing in sync queue
                Expect(batchComplete.resources)
                .To.Contain.Exactly(1)
                .Matched.By(
                    resource => resource.RelativePath == "missing"
                    );
                Expect(batchComplete.resources)
                .To.Contain.Exactly(1)
                .Matched.By(
                    resource => resource.RelativePath == "partial"
                    );

                Expect(notifiable.ResourceNotifications)
                .To.Contain.Exactly(2)
                .Items();
                var missingResource = notifiable.ResourceNotifications.First();

                Expect(missingResource.source.RelativePath)
                .To.Equal("missing");
                Expect(missingResource.source.Size)
                .To.Equal(missingData.Length);
                Expect(missingResource.target)
                .To.Be.Null();
                var partialResource = notifiable.ResourceNotifications.Second();

                Expect(partialResource.source.RelativePath)
                .To.Equal("partial");
                Expect(partialResource.source.Size)
                .To.Equal(partialFileAllData.Length);
                Expect(partialResource.target.RelativePath)
                .To.Equal("partial");
                Expect(partialResource.target.Size)
                .To.Equal(partialTargetData.Length);

                Expect(notifiable.CompletedNotifications)
                .To.Contain.Exactly(2)
                .Items();
                missingResource = notifiable.CompletedNotifications.First();
                Expect(missingResource.source.RelativePath)
                .To.Equal("missing");
                Expect(missingResource.source.Size)
                .To.Equal(missingData.Length);
                Expect(missingResource.target)
                .Not.To.Be.Null();
                Expect(missingResource.target.RelativePath)
                .To.Equal("missing");
                Expect(missingResource.target.Size)
                .To.Equal(missingData.Length);
                partialResource = notifiable.CompletedNotifications.Second();
                Expect(partialResource.source.RelativePath)
                .To.Equal("partial");
                Expect(partialResource.source.Size)
                .To.Equal(partialFileAllData.Length);
                Expect(partialResource.target.RelativePath)
                .To.Equal("partial");
                Expect(partialResource.target.Size)
                .To.Equal(partialTargetData.Length);
            }