public void ReturnsNullIfApplicationFolderIsNotAccessible()
            {
                var folder = new StubPlatformFolder { OnGetFiles = () => { throw new UnauthorizedAccessException(); } };
                var provider = new StubApplicationFolderProvider { OnGetApplicationFolder = () => folder };
                var storage = new TransmissionStorage(provider);

                Transmission result = storage.Dequeue();

                Assert.Null(result);
            }
            public void SkipsTransmissionFileAlreadyLoadedByAnotherThreadAndTriesLoadingNextFile()
            {
                var files = new List<IPlatformFile>();

                StubPlatformFile loadedFile = CreateTransmissionFile();
                loadedFile.OnRename = newName =>
                {
                    files.Remove(loadedFile);
                    throw new FileNotFoundException();
                };

                StubPlatformFile nextFile = CreateTransmissionFile();

                files.Add(loadedFile);
                files.Add(nextFile);
                var folder = new StubPlatformFolder { OnGetFiles = () => files };
                var provider = new StubApplicationFolderProvider { OnGetApplicationFolder = () => folder };
                var storage = new TransmissionStorage(provider);

                Transmission dequeued = storage.Dequeue();

                Assert.NotNull(dequeued);
            }
            public void SkipsTransmissionFileBeingCurrentlyLoadedByAnotherThreadAndTriesLoadingNextFile()
            {
                var files = new List<IPlatformFile>();

                StubPlatformFile fileBeingLoadedByAnotherThread = CreateTransmissionFile();
                fileBeingLoadedByAnotherThread.OnRename = newName =>
                {
                    files.Remove(fileBeingLoadedByAnotherThread);
                    throw new UnauthorizedAccessException();
                };

                StubPlatformFile nextFile = CreateTransmissionFile();

                files.Add(fileBeingLoadedByAnotherThread);
                files.Add(nextFile);
                var folder = new StubPlatformFolder { OnGetFiles = () => files };
                var provider = new StubApplicationFolderProvider { OnGetApplicationFolder = () => folder };
                var storage = new TransmissionStorage(provider);

                Transmission dequeued = storage.Dequeue();

                Assert.NotNull(dequeued);
            }
            public void GetsMultipleFilesFromFolderOnceAndCachesThemToReduceDiskAccess()
            {
                int numberOfGetFilesAsyncCalls = 0;
                var files = new StubPlatformFile[] { CreateTransmissionFile(), CreateTransmissionFile() };
                var folder = new StubPlatformFolder();
                folder.OnGetFiles = () =>
                {
                    numberOfGetFilesAsyncCalls += 1;
                    return files;
                };
                var provider = new StubApplicationFolderProvider { OnGetApplicationFolder = () => folder };
                var storage = new TransmissionStorage(provider);

                Assert.NotNull(storage.Dequeue());
                Assert.NotNull(storage.Dequeue());
                Assert.Equal(2, numberOfGetFilesAsyncCalls); // 1 for initializing size and 1 for 1 dequeue
            }
            public void DoesNotCacheSameFilesTwiceWhenIvokedByMultipleThreads()
            {
                int numberOfGetFilesAsyncCalls = 0;
                var returnFiles = new ManualResetEventSlim();
                var files = new StubPlatformFile[] { CreateTransmissionFile(), CreateTransmissionFile() };
                var folder = new StubPlatformFolder();
                folder.OnGetFiles = () =>
                {
                    numberOfGetFilesAsyncCalls += 1;
                    returnFiles.Wait();
                    return files;
                };
                var provider = new StubApplicationFolderProvider { OnGetApplicationFolder = () => folder };
                var storage = new TransmissionStorage(provider);

                Task<Transmission> dequeue1 = TaskEx.Run(() => storage.Dequeue());
                Task<Transmission> dequeue2 = TaskEx.Run(() => storage.Dequeue());
                returnFiles.Set();
                TaskEx.WhenAll(dequeue1, dequeue2).GetAwaiter().GetResult();

                Assert.Equal(2, numberOfGetFilesAsyncCalls); // 1 for initializing size and 1 for 1 dequeue
            }
            public void ReturnsFalseDoesNotEnqueueIfProcessHasNoRightToListFilesInApplicationFolder()
            {
                var folder = new StubPlatformFolder { OnGetFiles = () => { throw new UnauthorizedAccessException(); } };
                var provider = new StubApplicationFolderProvider { OnGetApplicationFolder = () => folder };
                var storage = new TransmissionStorage(provider);

                storage.Enqueue(() => new StubTransmission());

                bool result = storage.Enqueue(() => new StubTransmission());

                Assert.False(result);
            }
            public void ReturnsFalseIfProcessHasNoRightToWriteToFilesInApplicationFolder()
            {
                var file = new StubPlatformFile { OnOpen = () => { throw new UnauthorizedAccessException(); } };
                var folder = new StubPlatformFolder { OnCreateFile = name => file };
                var provider = new StubApplicationFolderProvider { OnGetApplicationFolder = () => folder };
                var storage = new TransmissionStorage(provider);

                bool result = storage.Enqueue(() => new StubTransmission());

                Assert.False(result);
            }
            public void ChangesTemporaryExtensionToPermanentToMakeFileAvailableForDequeueAsync()
            {
                string permanentFileName = null;
                StubPlatformFile file = CreateFile("TemporaryFile");
                file.OnRename = desiredName => permanentFileName = desiredName;
                var folder = new StubPlatformFolder { OnCreateFile = fileName => file };
                var provider = new StubApplicationFolderProvider { OnGetApplicationFolder = () => folder };
                var storage = new TransmissionStorage(provider);

                storage.Enqueue(() => new StubTransmission());

                Assert.True(permanentFileName.EndsWith(TransmissionStorage.TransmissionFileExtension, StringComparison.OrdinalIgnoreCase));
            }
            public void ClosesFileStreamToEnsureChangesAreCommittedToDisk()
            {
                bool fileStreamDisposed = false;
                var fileStream = new StubStream { OnDispose = disposing => fileStreamDisposed = true };
                var file = new StubPlatformFile { OnOpen = () => fileStream };
                var folder = new StubPlatformFolder { OnCreateFile = fileName => file };
                var provider = new StubApplicationFolderProvider { OnGetApplicationFolder = () => folder };
                var storage = new TransmissionStorage(provider);

                storage.Enqueue(() => new StubTransmission());
                
                Assert.True(fileStreamDisposed);
            }
            public void SavesTransmissionToTheNewlyCreatedFile()
            {
                string writtenContents = null;
                StubStream fileStream = new StubStream();
                fileStream.OnDispose = disposing =>
                {
                    writtenContents = Encoding.UTF8.GetString(fileStream.ToArray());
                };

                var file = new StubPlatformFile { OnOpen = () => fileStream };
                var folder = new StubPlatformFolder { OnCreateFile = fileName => file };
                var provider = new StubApplicationFolderProvider { OnGetApplicationFolder = () => folder };
                var storage = new TransmissionStorage(provider);

                byte[] contents = Encoding.UTF8.GetBytes(Path.GetRandomFileName());
                var transmission = new StubTransmission(contents);
                storage.Enqueue(() => transmission);
                
                string encodedContent = writtenContents.Split(Environment.NewLine.ToCharArray()).Last();
                Assert.Equal(contents, Convert.FromBase64String(encodedContent));
            }
            public void CreatesFilesWithUniqueNamesToPreventConflictsWithOtherThreads()
            {
                var actualFileNames = new List<string>();
                var folder = new StubPlatformFolder
                {
                    OnCreateFile = fileName =>
                    {
                        actualFileNames.Add(fileName);
                        return new StubPlatformFile();
                    }
                };
                var provider = new StubApplicationFolderProvider { OnGetApplicationFolder = () => folder };
                var storage = new TransmissionStorage(provider);

                storage.Enqueue(() => new StubTransmission());
                storage.Enqueue(() => new StubTransmission());

                Assert.NotEqual(actualFileNames[0], actualFileNames[1]);
            }
            public void CreatesNewFileWithTemporaryExtensionToPreventConflictsWithDequeueAsync()
            {
                string temporaryFileName = null;
                var folder = new StubPlatformFolder
                {
                    OnCreateFile = fileName =>
                    {
                        temporaryFileName = fileName;
                        return new StubPlatformFile();
                    }
                };
                var provider = new StubApplicationFolderProvider { OnGetApplicationFolder = () => folder };
                var storage = new TransmissionStorage(provider);

                storage.Enqueue(() => new StubTransmission());

                Assert.True(temporaryFileName.EndsWith(TransmissionStorage.TemporaryFileExtension, StringComparison.OrdinalIgnoreCase));
            }