public async Task FileSystemPublicSuffixDataSource_GetDataAsync_WhenDiskDataExistsAndIsStaleButNotExpired_ReturnsStaleDataAndFetchesNewFromUpstream() { Mocked<IFileSystem>() .Setup(fs => fs.Exists(_cacheFilePath)) .Returns(true); Mocked<IFileSystem>() .Setup(fs => fs.GetLastWriteTime(_cacheFilePath)) .Returns(DateTime.Now.AddDays(-11)); Mocked<IFileSystem>() .Setup(fs => fs.OpenRead(_cacheFilePath)) .Returns(new MemoryStream(Encoding.UTF8.GetBytes("{ \"com\": { } }"))); var latestData = new DomainSegmentTree { Children = new DomainSegmentNodeCollection { new DomainSegmentNode {Segment = "com"}, new DomainSegmentNode {Segment = "net"} } }; var upstreamSource = new Mock<IPublicSuffixDataSource>(); upstreamSource.Setup(s => s.GetDataAsync()).Returns(Task.FromResult(latestData)); Subject.Upstream = upstreamSource.Object; var data = await Subject.GetDataAsync(); data.Children.Should().HaveCount(1); data.Contains("com").Should().BeTrue(); upstreamSource.Verify(s => s.GetDataAsync()); // Wait for cache to be asynchronously written await Task.Delay(100); Mocked<IFileSystem>().Verify(fs => fs.OpenWrite(_cacheFilePath)); }
public async Task GetDataAsync_AlwaysGetsDataFromUpstreamAtFirst() { var upstreamData = new DomainSegmentTree(); Mocked<IPublicSuffixDataSource>() .Setup(s => s.GetDataAsync()) .Returns(Task.FromResult(upstreamData)); var data = await Subject.GetDataAsync(); data.Should().Be(upstreamData); }
protected override Task CacheUpstreamDataAsync(DomainSegmentTree data) { return Task.Run(() => { var serializer = new JsonSerializer(); using (var stream = _fileSystem.OpenWrite(_config.CacheFilePath)) using (var writer = new StreamWriter(stream)) { var json = ConvertToJsonRecursive(data); serializer.Serialize(writer, json); } }); }
public async Task GetDataAsync_CachesUpstreamData() { var upstreamData = new DomainSegmentTree(); Mocked<IPublicSuffixDataSource>() .Setup(s => s.GetDataAsync()) .Returns(Task.FromResult(upstreamData)); Subject.Upstream = Mocked<IPublicSuffixDataSource>().Object; await Subject.GetDataAsync(); await Task.Delay(100); await Subject.GetDataAsync(); Mocked<IPublicSuffixDataSource>().Verify(ds => ds.GetDataAsync(), Times.Once()); }
private static IEnumerable<string> GetTldSegments(DomainSegmentTree tree, IEnumerable<string> segments) { var node = tree; foreach (var segment in segments) { if (node.Contains(segment)) { yield return segment; node = node[segment]; } else if (!node.Contains("!" + segment) && node.Contains("*")) { yield return segment; node = node["*"]; } else { break; } } }
protected override async Task<DomainSegmentTree> GetCurrentDataAsync() { var tree = new DomainSegmentTree(); using (var client = _httpFactory.GetHttpClient()) using (var stream = await client.GetStreamAsync(_config.DataSourceUrl)) using (var reader = new StreamReader(stream)) { while (!reader.EndOfStream) { var line = await reader.ReadLineAsync(); if (!IsOfSubstance(line)) continue; line.Split('.') .Reverse() .Aggregate(tree, (current, segment) => current[segment] ?? current.Add(segment)); } } return tree; }
protected abstract Task CacheUpstreamDataAsync(DomainSegmentTree data);
protected override Task CacheUpstreamDataAsync(DomainSegmentTree data) { throw new NotImplementedException(); }
private static JObject ConvertToJsonRecursive(DomainSegmentTree tree) { return new JObject( from node in tree.Children ?? Enumerable.Empty<DomainSegmentNode>() select new JProperty(node.Segment, ConvertToJsonRecursive(node))); }
protected override async Task CacheUpstreamDataAsync(DomainSegmentTree data) { _cache = data; _cacheTime = DateTime.Now; }
public async Task FileSystemPublicSuffixDataSource_GetDataAsync_RaisesAnEventWhenReceivingErrorCachingUpstreamData() { var ioException = new IOException(); Mocked<IFileSystem>() .Setup(fs => fs.Exists(_cacheFilePath)) .Returns(false); Mocked<IFileSystem>() .Setup(fs => fs.OpenWrite(_cacheFilePath)) .Throws(ioException); var latestData = new DomainSegmentTree { Children = new DomainSegmentNodeCollection { new DomainSegmentNode {Segment = "com"}, new DomainSegmentNode {Segment = "net"} } }; var upstreamSource = new Mock<IPublicSuffixDataSource>(); upstreamSource.Setup(s => s.GetDataAsync()).Returns(Task.FromResult(latestData)); Exception cacheException = null; Subject.CacheError += (s, e) => cacheException = e.Exception; Subject.Upstream = upstreamSource.Object; await Subject.GetDataAsync(); await Task.Delay(100); cacheException.Should().Be(ioException); }
public async Task FileSystemPublicSuffixDataSource_GetDataAsync_CachesAfterGettingDataFromUpstream() { var mockStream = new MemoryStream(); Mocked<IFileSystem>() .Setup(fs => fs.Exists(_cacheFilePath)) .Returns(false); Mocked<IFileSystem>() .Setup(fs => fs.OpenWrite(_cacheFilePath)) .Returns(mockStream); var latestData = new DomainSegmentTree { Children = new DomainSegmentNodeCollection { new DomainSegmentNode {Segment = "com"}, new DomainSegmentNode {Segment = "net"} } }; var upstreamSource = new Mock<IPublicSuffixDataSource>(); upstreamSource.Setup(s => s.GetDataAsync()).Returns(Task.FromResult(latestData)); Subject.Upstream = upstreamSource.Object; await Subject.GetDataAsync(); // Hack... wait for the cache to be written await Task.Delay(100); var serializer = new JsonSerializer(); var buffer = mockStream.GetBuffer(); using (var readStream = new MemoryStream(buffer)) using (var textReader = new StreamReader(readStream)) using (var reader = new JsonTextReader(textReader)) { var obj = serializer.Deserialize<JObject>(reader); obj.Properties().Should().HaveCount(2); obj["com"].Should().NotBeNull(); obj["net"].Should().NotBeNull(); } }
public async Task FileSystemPublicSuffixDataSource_GetDataAsync_WhenReadingDiskDataFails_ReturnsDataFromUpstream() { Mocked<IFileSystem>() .Setup(fs => fs.Exists(_cacheFilePath)) .Returns(true); Mocked<IFileSystem>() .Setup(fs => fs.GetLastWriteTime(_cacheFilePath)) .Returns(DateTime.Now); Mocked<IFileSystem>() .Setup(fs => fs.OpenRead(_cacheFilePath)) .Throws(new IOException()); var latestData = new DomainSegmentTree { Children = new DomainSegmentNodeCollection { new DomainSegmentNode {Segment = "com"}, new DomainSegmentNode {Segment = "net"} } }; var upstreamSource = new Mock<IPublicSuffixDataSource>(); upstreamSource.Setup(s => s.GetDataAsync()).Returns(Task.FromResult(latestData)); Subject.Upstream = upstreamSource.Object; var data = await Subject.GetDataAsync(); data.Should().Be(latestData); }
public async Task FileSystemPublicSuffixDataSource_GetDataAsync_WhenDiskDataDoesNotExist_ReturnsNewDataFromUpstream() { Mocked<IFileSystem>() .Setup(fs => fs.Exists(_cacheFilePath)) .Returns(false); var latestData = new DomainSegmentTree { Children = new DomainSegmentNodeCollection { new DomainSegmentNode {Segment = "com"}, new DomainSegmentNode {Segment = "net"} } }; var upstreamSource = new Mock<IPublicSuffixDataSource>(); upstreamSource.Setup(s => s.GetDataAsync()).Returns(Task.FromResult(latestData)); Subject.Upstream = upstreamSource.Object; var data = await Subject.GetDataAsync(); data.Should().Be(latestData); }
public async Task FileSystemPublicSuffixDataSource_GetDataAsync_WhenDiskDataExistsAndIsExpired_ReturnsNewDataFromUpstream() { Mocked<IFileSystem>() .Setup(fs => fs.GetLastWriteTime(_cacheFilePath)) .Returns(DateTime.Now.AddDays(-11)); Mocked<IFileSystem>() .Setup(fs => fs.OpenRead(_cacheFilePath)) .Returns(new MemoryStream(Encoding.UTF8.GetBytes("{ \"com\": { } }"))); var latestData = new DomainSegmentTree { Children = new DomainSegmentNodeCollection { new DomainSegmentNode {Segment = "com"}, new DomainSegmentNode {Segment = "net"} } }; var upstreamSource = new Mock<IPublicSuffixDataSource>(); upstreamSource.Setup(s => s.GetDataAsync()).Returns(Task.FromResult(latestData)); Subject.Upstream = upstreamSource.Object; var data = await Subject.GetDataAsync(); data.Should().Be(latestData); }