public void Start_WhenFileNotificationIsYield_ShouldCallSynchronize( [Frozen]TestScheduler scheduler, [Frozen(As = typeof(IObservable<MusicMirrorConfiguration>))]TestObservableWrapper<MusicMirrorConfiguration> configurationObservable, [Frozen]Mock<IFileObserverFactory> fileObserverFactory, [Frozen]Mock<IFileSynchronizerVisitorFactory> fileSynchronizerFactory, SynchronizeFilesWhenFileChanged sut, MusicMirrorConfiguration configuration, IFileNotification[][] fileNotification, Mock<IFileSynchronizerVisitor> fileSynchronizerVisitor) { //arrange configurationObservable.SetObservable(scheduler.CreateHotObservable(OnNext(Subscribed + 1, configuration))); const long NotificationsStart = Subscribed + 2; var fileObserver = scheduler.CreateHotObservable( fileNotification.Select((f, i) => OnNext(NotificationsStart + i, f)).ToArray()); fileObserverFactory.Setup(f => f.GetFileObserver(configuration.SourcePath)).Returns(fileObserver); fileSynchronizerFactory.Setup(f => f.CreateVisitor(configuration)).Returns(fileSynchronizerVisitor.Object); //act sut.Start(); scheduler.Start(); //assert foreach (var m in fileNotification.SelectMany(f => f).Select(f => Mock.Get(f))) { m.Verify(ff => ff.Accept(It.IsAny<CancellationToken>(), fileSynchronizerVisitor.Object)); } }
public CopyFileSynchronizer( MusicMirrorConfiguration configuration, IAsyncDirectoryOperations directoryOperations) { _configuration = Guard.ForNull(configuration, nameof(configuration)); _directoryOperations = Guard.ForNull(directoryOperations, nameof(directoryOperations)); }
public IFileSynchronizerVisitor CreateVisitor(MusicMirrorConfiguration configuration) { var fileSynchronizerRepository = new SynchronizedFilesRepository( _transcoder, configuration, new SystemUtcNow()); var fileOperations = new AsyncOperations(new FileOperations()); var transcodingMirroredFileOperations = new SynchronizeFileService( fileOperations, configuration, new FileSynchronizer( fileSynchronizerRepository, _transcoder), fileSynchronizerRepository); var nonTranscodingFileService = new SynchronizeFileService( GetFileOperations(configuration.NonTranscodingFilesBehavior, fileOperations), configuration, GetSynchronizer(configuration, fileOperations, new AsyncDirectoryOperations(new DirectoryOperations())), fileSynchronizerRepository); return new FileSynchronizeVisitor( new ChooseFolderOperation( new DefaultRequireTranscoding(), nonTranscodingFileService, transcodingMirroredFileOperations)); }
public static DirectoryInfo GetDirectoryFromSourceFile(this FileInfo sourceFile, MusicMirrorConfiguration configuration) { if (sourceFile == null) throw new ArgumentNullException(nameof(sourceFile)); if (configuration == null) throw new ArgumentNullException(nameof(configuration)); var relativePath = Path.GetDirectoryName(sourceFile.FullName.Replace(configuration.SourcePath.FullName, string.Empty)).TrimStart('\\'); return new DirectoryInfo(Path.Combine(configuration.TargetPath.FullName, relativePath)); }
public async Task Synchronize_WhenLastSynchronizationTimeIsMoreRecentThanFileModificationDate_ShouldNotCallTranscode( double daysToAdd, [Frozen]Mock<ISynchronizedFilesRepository> synchronizedFileRepository, [Frozen]Mock<IFileTranscoder> fileTranscoder, MusicMirrorConfiguration config, FileSynchronizer sut, SourceFilePath sourceFile, TargetFilePath targetFile) { //arrange var lastWriteTime = new DateTimeOffset(2015, 04, 01, 0, 0, 0, TimeSpan.Zero); var lastSyncTime = lastWriteTime.AddDays(daysToAdd); sourceFile.LastWriteTime = lastWriteTime; synchronizedFileRepository.Setup(s => s.GetMirroredFilePath(It.IsAny<CancellationToken>(), sourceFile.File)).ReturnsTask(targetFile.File); synchronizedFileRepository.Setup(s => s.GetLastSynchronization(It.IsAny<CancellationToken>(), sourceFile.File)).ReturnsTask(lastSyncTime); //act await sut.Synchronize(CancellationToken.None, sourceFile); //assert fileTranscoder.Verify(f => f.Transcode( It.IsAny<CancellationToken>(), sourceFile.File, AudioFormat.Flac, It.Is((DirectoryInfo d) => d.FullName.Equals(targetFile.File.DirectoryName))), Times.Never()); }
public SymbolicLinkFileSynchronizer( MusicMirrorConfiguration configuration, IAsyncFileOperations fileOperations, IAsyncDirectoryOperations directoryOperations) { _configuration = Guard.ForNull(configuration, nameof(configuration)); _fileOperations = Guard.ForNull(fileOperations, nameof(fileOperations)); _directoryOperations = Guard.ForNull(directoryOperations, nameof(directoryOperations)); }
public static TargetFilePath CreateFromPathWithoutExtension( MusicMirrorConfiguration config, string[] relativePathParts) { return new TargetFilePath( config.TargetPath.FullName, relativePathParts.Skip(1).ToArray(), relativePathParts[0] + ".mp3"); }
public static SourceFilePath CreateFromPathWithoutExtension( MusicMirrorConfiguration config, string[] relativePathParts) { return new SourceFilePath( config.SourcePath.FullName, relativePathParts.Skip(1).ToArray(), relativePathParts[0] + ".flac"); }
public async Task Synchronize_ShouldCallInnerSynchronize( [Frozen]Mock<IFileTranscoder> innerFileTranscoder, CopyId3TagsPostProcessor sut, SourceFilePath sourceFile, MusicMirrorConfiguration configuration) { //arrange //act await sut.Transcode(CancellationToken.None, sourceFile.File, AudioFormat.Flac, configuration.TargetPath); //assert innerFileTranscoder.Verify(f => f.Transcode(It.IsAny<CancellationToken>(), sourceFile.File, AudioFormat.Flac, configuration.TargetPath)); }
public SynchronizedFilesRepository( IFileTranscoder fileTranscoder, MusicMirrorConfiguration configuration, INow now) { if (now == null) throw new ArgumentNullException(nameof(now), $"{nameof(now)} is null."); if (fileTranscoder == null) throw new ArgumentNullException(nameof(fileTranscoder)); if (configuration == null) throw new ArgumentNullException(nameof(configuration)); _fileTranscoder = fileTranscoder; _configuration = configuration; _now = now; _synchronizations = new ConcurrentDictionary<string, DateTimeOffset>(); }
public SynchronizeFileService( IAsyncFileOperations asyncFileOperations, MusicMirrorConfiguration configuration, IFileSynchronizer fileSynchronizer, ISynchronizedFilesRepository synchronizedFilesRepository) { if (asyncFileOperations == null) throw new ArgumentNullException(nameof(asyncFileOperations)); if (configuration == null) throw new ArgumentNullException(nameof(configuration)); if (fileSynchronizer == null) throw new ArgumentNullException(nameof(fileSynchronizer)); if (synchronizedFilesRepository == null) throw new ArgumentNullException(nameof(synchronizedFilesRepository)); _asyncFileOperations = asyncFileOperations; _configuration = configuration; _fileSynchronizer = fileSynchronizer; _synchronizedFilesRepository = synchronizedFilesRepository; }
public void Sut_ShouldReturnCorrectValue( [Frozen]Mock<ISettingsService> settingsService, ConfigurationObservable sut, TestScheduler scheduler, MusicMirrorConfiguration expected) { //arrange settingsService.Setup(s => s.ObserveValue(ConfigurationObservable.SourcePathKey, It.IsAny<Func<string>>())) .Returns(scheduler.CreateColdObservable(OnNext(0, expected.SourcePath.FullName))); settingsService.Setup(s => s.ObserveValue(ConfigurationObservable.TargetPathKey, It.IsAny<Func<string>>())) .Returns(scheduler.CreateColdObservable(OnNext(0, expected.TargetPath.FullName))); //act var result = scheduler.Start(() => sut); //assert result.Values().First().Should().Be(expected); }
public IFileSynchronizerVisitor CreateVisitor(MusicMirrorConfiguration configuration) { return new LoggingFileSynchronizerVisitor(_innerFactory.CreateVisitor(configuration), _log); }
public IFileSynchronizerVisitor CreateVisitor(MusicMirrorConfiguration configuration) { return new EmptyFileSynchronizerVisitor(); }
public void ObserveTranscodingResult_WhenFileNotificationIsYield_ShouldReturnCorrectValue( [Frozen]TestScheduler scheduler, [Frozen(As = typeof(IObservable<MusicMirrorConfiguration>))]TestObservableWrapper<MusicMirrorConfiguration> configurationObservable, [Frozen]Mock<IFileObserverFactory> fileObserverFactory, [Frozen]Mock<IFileSynchronizerVisitorFactory> fileSynchronizerFactory, SynchronizeFilesWhenFileChanged sut, MusicMirrorConfiguration configuration, IFileNotification[][] fileNotification, Mock<IFileSynchronizerVisitor> fileSynchronizerVisitor) { //arrange sut.SynchronizationScheduler = ImmediateScheduler.Instance; configurationObservable.SetObservable(scheduler.CreateHotObservable(OnNext(Subscribed + 1, configuration))); const long NotificationsStart = Subscribed + 2; var fileObserver = scheduler.CreateHotObservable( fileNotification.Select((f, i) => OnNext(NotificationsStart + i, f)).ToArray()); fileObserverFactory.Setup(f => f.GetFileObserver(configuration.SourcePath)).Returns(fileObserver); fileSynchronizerFactory.Setup(f => f.CreateVisitor(configuration)).Returns(fileSynchronizerVisitor.Object); scheduler.Schedule(200.Ticks(), () => sut.Start()); //act var actual = scheduler.Start(() => sut.ObserveTranscodingResult()); //assert var expected = fileNotification.SelectMany( (notifications, i) => notifications.Select( f => new FileTranscodingResultNotification.SuccessTranscodingResultNotification(f)) ).ToArray(); actual.Values().ShouldAllBeEquivalentTo(expected, o => o.RespectingRuntimeTypes()); }
private static IFileSynchronizer GetSynchronizer(MusicMirrorConfiguration configuration, IAsyncFileOperations fileOperations, IAsyncDirectoryOperations directoryOperations) { switch (configuration.NonTranscodingFilesBehavior) { case NonTranscodingFilesBehavior.Copy: return new CopyFileSynchronizer(configuration, directoryOperations); case NonTranscodingFilesBehavior.SymbolicLink: return new SymbolicLinkFileSynchronizer(configuration, fileOperations, directoryOperations); default: throw new NotSupportedException(); } }
public void ObserveIsTranscodingRunning_WhenFilesAreTranscodingAndSubscribeOccursLaterOn_ShouldReturnCorrectValue( [Frozen]TestScheduler scheduler, [Frozen(As = typeof(IObservable<MusicMirrorConfiguration>))]TestObservableWrapper<MusicMirrorConfiguration> configurationObservable, [Frozen]Mock<IFileObserverFactory> fileObserverFactory, SynchronizeFilesWhenFileChanged sut, MusicMirrorConfiguration configuration, IFileNotification[] fileNotification ) { sut.SynchronizationScheduler = ImmediateScheduler.Instance; const long NotificationsStart = Subscribed + 1; const long Subscription = Subscribed + 3; configurationObservable.SetObservable(scheduler.CreateHotObservable(OnNext(NotificationsStart, configuration))); var fileObserver = scheduler.CreateHotObservable(OnNext(NotificationsStart, fileNotification)); fileObserverFactory.Setup(f => f.GetFileObserver(configuration.SourcePath)).Returns(fileObserver); SetupTranscodingWorkWithIncrementalDuration(scheduler, fileNotification); scheduler.Schedule(200.Ticks(), () => sut.Start()); //act var actual = scheduler.Start(() => sut.ObserveIsTranscodingRunning(), Created, Subscription, Disposed); //assert var expected = new[] { true, false }; //+1 because we expect that the tasks results of file.Accept will be scheduled on the TestScheduler actual.Values().ShouldAllBeEquivalentTo(expected); }
public void ObserveIsTranscodingRunning_WhenFilesAreTranscoding_ShouldReturnCorrectValue( [Frozen]TestScheduler scheduler, [Frozen(As = typeof(IObservable<MusicMirrorConfiguration>))]TestObservableWrapper<MusicMirrorConfiguration> configurationObservable, [Frozen]Mock<IFileObserverFactory> fileObserverFactory, SynchronizeFilesWhenFileChanged sut, MusicMirrorConfiguration configuration, IFileNotification[] fileNotification ) { //arrange sut.SynchronizationScheduler = ImmediateScheduler.Instance; configurationObservable.SetObservable(scheduler.CreateHotObservable(OnNext(Subscribed + 1, configuration))); const long NotificationsStart = Subscribed + 2; var fileObserver = scheduler.CreateHotObservable(OnNext(NotificationsStart, fileNotification)); fileObserverFactory.Setup(f => f.GetFileObserver(configuration.SourcePath)).Returns(fileObserver); SetupTranscodingWorkWithIncrementalDuration(scheduler, fileNotification); scheduler.Schedule(200.Ticks(), () => sut.Start()); //act var actual = scheduler.Start(() => sut.ObserveIsTranscodingRunning()); //assert var expected = new[] { false, true, false }; actual.Values().ShouldAllBeEquivalentTo(expected); }
public async Task Synchronize_WhenFormatIsUknown_ShouldNotCallTranscode( [Frozen]Mock<ISynchronizedFilesRepository> synchronizedFileRepository, [Frozen]Mock<IFileTranscoder> fileTranscoder, MusicMirrorConfiguration config, FileSynchronizer sut, TargetFilePath targetFile) { //arrange var expectedExtension = ".uknownExtension"; var sourceFile = new SourceFilePath(config.SourcePath.FullName, new[] { "test", "test" }, "test" + expectedExtension); var lastWriteTime = new DateTimeOffset(2015, 04, 01, 0, 0, 0, TimeSpan.Zero); var lastSyncTime = lastWriteTime.AddDays(-1); sourceFile.LastWriteTime = lastWriteTime; synchronizedFileRepository.Setup(s => s.GetMirroredFilePath(It.IsAny<CancellationToken>(), sourceFile.File)).ReturnsTask(targetFile.File); synchronizedFileRepository.Setup(s => s.GetLastSynchronization(It.IsAny<CancellationToken>(), sourceFile.File)).ReturnsTask(lastSyncTime); var expectedFormat = new AudioFormat("Uknown format", "Uknown format", expectedExtension, default(LossKind)); //act await sut.Synchronize(CancellationToken.None, sourceFile); //assert fileTranscoder.Verify(f => f.Transcode( It.IsAny<CancellationToken>(), sourceFile.File, expectedFormat, It.Is((DirectoryInfo d) => d.FullName.Equals(targetFile.File.DirectoryName)))); }
public void Sut_WhenUsingDefaultValue_ShouldReturnCorrectValue( [Frozen]Mock<ISettingsService> settingsService, ConfigurationObservable sut, TestScheduler scheduler ) { //arrange settingsService.Setup(s => s.ObserveValue(ConfigurationObservable.SourcePathKey, It.IsAny<Func<string>>())) .Returns<string, Func<string>>((key, defaultValue) => scheduler.CreateColdObservable( OnNext(0, defaultValue()) )); settingsService.Setup(s => s.ObserveValue(ConfigurationObservable.TargetPathKey, It.IsAny<Func<string>>())) .Returns<string, Func<string>>((key, defaultValue) => scheduler.CreateColdObservable( OnNext(0, defaultValue()) )); var expected = new MusicMirrorConfiguration(null, null, NonTranscodingFilesBehavior.Copy); //act var result = scheduler.Start(() => sut); //assert result.Values().First().ShouldBeEquivalentTo(expected); }
private IObservable<Unit> ObserveFiles(MusicMirrorConfiguration configuration) { var visitor = FileSynchronizerVisitorFactory.CreateVisitor(configuration); return FileObserverFactory.GetFileObserver(configuration.SourcePath) .ObserveOn(_notificationsScheduler) .Do(files => { _numberOfFilesAddedInTranscodingQueue.OnNext(files.Length); _fileNotifications.OnNext(files); }) .SelectMany(files => files.Select(file => SynchronizeFile(file, visitor)) .Merge(4, _synchronizationScheduler) .ToList() .SelectUnit()); }
public void ObserveFileNotifications_Start_WhenFileNotificationIsYield_ShouldCallSynchronize( [Frozen]TestScheduler scheduler, [Frozen(As = typeof(IObservable<MusicMirrorConfiguration>))]TestObservableWrapper<MusicMirrorConfiguration> configurationObservable, [Frozen]Mock<IFileObserverFactory> fileObserverFactory, SynchronizeFilesWhenFileChanged sut, MusicMirrorConfiguration configuration, IFileNotification[][] fileNotification) { //arrange configurationObservable.SetObservable(scheduler.CreateHotObservable(OnNext(Subscribed + 1, configuration))); var expectedNotifications = fileNotification.Select((f, i) => OnNext(Subscribed + i + 2, f)).ToArray(); var fileObserver = scheduler.CreateHotObservable(expectedNotifications); fileObserverFactory.Setup(f => f.GetFileObserver(configuration.SourcePath)).Returns(fileObserver); scheduler.Schedule(200.Ticks(), () => sut.Start()); //act var actual = scheduler.Start(() => sut.ObserveNotifications()); //assert var expected = expectedNotifications.Select(n => n.Value.Value); actual.Values().ShouldAllBeEquivalentTo(expected); }