Ejemplo n.º 1
0
        private static async Task <ImmutableDictionary <HttpRequestMessage, HttpResponseMessage> > ReadCacheAsync(string fileName)
        {
            var      result = ImmutableDictionary.CreateBuilder <HttpRequestMessage, HttpResponseMessage>(HttpRequestEqualityComparer.Default);
            DateTime lastWriteTimeUtc;

            using (var cacheStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, useAsync: true))
            {
                lastWriteTimeUtc = File.GetLastWriteTimeUtc(fileName);
                await VerifyFileHeaderAsync(cacheStream);

                while (cacheStream.Position < cacheStream.Length)
                {
                    var request = await HttpMessageSerializer.DeserializeRequestAsync(cacheStream);

                    if (request == null)
                    {
                        break;
                    }

                    var response = await HttpMessageSerializer.DeserializeResponseAsync(cacheStream);

                    result[request] = response;

                    // Allow for extra line endings after the response for readability.
                    SkipBlankLines(cacheStream);
                }

                if (result.Count == 0)
                {
                    throw new BadCacheFileException("No cached responses found.");
                }
            }

            return(result.ToImmutable());
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Serializes the cache out to a file in the specified directory.
        /// </summary>
        /// <param name="updateLocation">The path to the directory to write new or updated cache entries to. May be null.</param>
        /// <returns>A task that tracks completion of the operation.</returns>
        internal async Task PersistCacheAsync(string updateLocation)
        {
            Requires.NotNullOrEmpty(updateLocation, nameof(updateLocation));
            Verify.Operation(this.cacheFilePath != null, "This instance cannot be persisted because it was not created with a path.");

            // We don't want to write files to the source directory of the test project if the test project isn't even there.
            string updateLocationNoTrailingSlash = updateLocation.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);

            Verify.Operation(Directory.GetParent(updateLocationNoTrailingSlash).Exists, "Caching an HTTP response to \"{0}\" requires that its parent directory already exist. Is the source code for the test not on this machine?", updateLocation);

            // Get in line to write to the cache so we avoid file conflicts.
            // We don't need to queue up a long line of redundant file saves,
            // so only queue one if no one is already waiting to start saving.
            if (Interlocked.Exchange(ref this.saveQueued, 1) == 0)
            {
                await this.savingCacheSemaphore.WaitAsync();

                try
                {
                    Directory.CreateDirectory(updateLocation);
                    string filePathToUpdate = Path.Combine(updateLocation, Path.GetFileName(this.cacheFilePath));

                    using (var fileStream = new FileStream(filePathToUpdate, FileMode.Create, FileAccess.Write, FileShare.None, 4096, useAsync: true))
                    {
                        await fileStream.WriteAsync(FileHeader, 0, FileHeader.Length);

                        // Snap the memory cache to save. But first, clear the saveQueued field so if anyone wants to persist changes made after this, they will queue themselves.
                        Volatile.Write(ref this.saveQueued, 0);
#if !NETSTANDARD1_3
                        Thread.MemoryBarrier();
#endif
                        var cacheDictionary = await Volatile.Read(ref this.cacheDictionary);

                        foreach (var entry in cacheDictionary)
                        {
                            await HttpMessageSerializer.SerializeAsync(entry.Key, fileStream);

                            await HttpMessageSerializer.SerializeAsync(entry.Value, fileStream);

                            await fileStream.WriteAsync(SpaceBetweenResponseAndRequest, 0, SpaceBetweenResponseAndRequest.Length);
                        }
                    }

                    // Protect against git normalizing line endings for this file.
                    await this.WriteGitAttributesFileAsync(updateLocation);
                }
                finally
                {
                    this.savingCacheSemaphore.Release();
                }
            }
        }