Refactored repo organization. Added Jenkinsfile.
This commit is contained in:
89
Props.Shop/Adafruit.Tests/Api/FakeProductListingManager.cs
Normal file
89
Props.Shop/Adafruit.Tests/Api/FakeProductListingManager.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Props.Shop.Adafruit.Api;
|
||||
using Props.Shop.Framework;
|
||||
|
||||
namespace Props.Shop.Adafruit.Tests.Api
|
||||
{
|
||||
public class FakeProductListingManager : IProductListingManager
|
||||
{
|
||||
private bool disposedValue;
|
||||
public DateTime? LastDownload { get; private set; }
|
||||
private ProductListingsParser parser = new ProductListingsParser();
|
||||
private readonly ConcurrentDictionary<string, ProductListing> activeProductListingUrls = new ConcurrentDictionary<string, ProductListing>();
|
||||
|
||||
|
||||
public Task<IReadOnlyDictionary<string, IList<ProductListing>>> ProductListings { get; private set; }
|
||||
|
||||
public async Task<ProductListing> GetProductListingFromIdentifier(string url)
|
||||
{
|
||||
if (disposedValue) throw new ObjectDisposedException("ProductListingManager");
|
||||
await ProductListings;
|
||||
return activeProductListingUrls[url];
|
||||
}
|
||||
|
||||
public void RefreshProductListings()
|
||||
{
|
||||
if (disposedValue) throw new ObjectDisposedException("ProductListingManager");
|
||||
if ((LastDownload != null && DateTime.UtcNow - LastDownload <= TimeSpan.FromMilliseconds(5 * 60 * 1000)) || (ProductListings != null && !ProductListings.IsCompleted)) return;
|
||||
ProductListings = DownloadListings();
|
||||
}
|
||||
|
||||
private Task<IReadOnlyDictionary<string, IList<ProductListing>>> DownloadListings()
|
||||
{
|
||||
if (disposedValue) throw new ObjectDisposedException("ProductListingManager");
|
||||
LastDownload = DateTime.UtcNow;
|
||||
using (Stream stream = File.OpenRead("./Assets/products.json"))
|
||||
{
|
||||
parser.BuildProductListings(stream);
|
||||
|
||||
}
|
||||
Dictionary<string, IList<ProductListing>> listingNames = new Dictionary<string, IList<ProductListing>>();
|
||||
activeProductListingUrls.Clear();
|
||||
foreach (ProductListing product in parser.ProductListings)
|
||||
{
|
||||
activeProductListingUrls.TryAdd(product.URL, product);
|
||||
IList<ProductListing> sameProducts = listingNames.GetValueOrDefault(product.Name);
|
||||
if (sameProducts == null)
|
||||
{
|
||||
sameProducts = new List<ProductListing>();
|
||||
listingNames.Add(product.Name, sameProducts);
|
||||
}
|
||||
|
||||
sameProducts.Add(product);
|
||||
}
|
||||
return Task.FromResult<IReadOnlyDictionary<string, IList<ProductListing>>>(listingNames);
|
||||
}
|
||||
|
||||
public void StartUpdateTimer(int delay = 300000, int period = 300000)
|
||||
{
|
||||
RefreshProductListings();
|
||||
}
|
||||
|
||||
public void StopUpdateTimer()
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
}
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
21
Props.Shop/Adafruit.Tests/Api/ListingParserTest.cs
Normal file
21
Props.Shop/Adafruit.Tests/Api/ListingParserTest.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Props.Shop.Adafruit.Api;
|
||||
using Xunit;
|
||||
|
||||
namespace Props.Shop.Adafruit.Tests
|
||||
{
|
||||
public class ListingParserTest
|
||||
{
|
||||
[Fact]
|
||||
public void TestParsing()
|
||||
{
|
||||
ProductListingsParser mockParser = new ProductListingsParser();
|
||||
using (Stream stream = File.OpenRead("./Assets/products.json"))
|
||||
{
|
||||
mockParser.BuildProductListings(stream);
|
||||
}
|
||||
Assert.NotEmpty(mockParser.ProductListings);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Props.Shop.Adafruit.Api;
|
||||
using Props.Shop.Adafruit.Persistence;
|
||||
using Props.Shop.Framework;
|
||||
using Xunit;
|
||||
|
||||
namespace Props.Shop.Adafruit.Tests.Api
|
||||
{
|
||||
public class LiveProductListingManagerTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task CacheTest()
|
||||
{
|
||||
// TODO: Improve testability of caching system, IProductListingManager, and implement here.
|
||||
//Given
|
||||
ProductListingsParser parser = new ProductListingsParser();
|
||||
using (Stream stream = File.OpenRead("./Assets/products.json"))
|
||||
{
|
||||
parser.BuildProductListings(stream);
|
||||
}
|
||||
Dictionary<string, IList<ProductListing>> listingNames = new Dictionary<string, IList<ProductListing>>();
|
||||
foreach (ProductListing product in parser.ProductListings)
|
||||
{
|
||||
IList<ProductListing> sameProducts = listingNames.GetValueOrDefault(product.Name);
|
||||
if (sameProducts == null)
|
||||
{
|
||||
sameProducts = new List<ProductListing>();
|
||||
listingNames.Add(product.Name, sameProducts);
|
||||
}
|
||||
|
||||
sameProducts.Add(product);
|
||||
}
|
||||
ProductListingCacheData cache = new ProductListingCacheData(listingNames);
|
||||
await Task.Delay(500);
|
||||
LiveProductListingManager mockLiveProductListingManager = new LiveProductListingManager(null, new Logger<LiveProductListingManager>(LoggerFactory.Create((builder) => builder.AddXUnit())), cache);
|
||||
//When
|
||||
mockLiveProductListingManager.RefreshProductListings();
|
||||
//Then
|
||||
Assert.True(cache.LastUpdatedUtc.Equals(mockLiveProductListingManager.LastDownload));
|
||||
Assert.NotEmpty(await mockLiveProductListingManager.ProductListings);
|
||||
}
|
||||
}
|
||||
}
|
21
Props.Shop/Adafruit.Tests/Api/SearchManagerTest.cs
Normal file
21
Props.Shop/Adafruit.Tests/Api/SearchManagerTest.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Props.Shop.Adafruit.Api;
|
||||
using Xunit;
|
||||
|
||||
namespace Props.Shop.Adafruit.Tests.Api
|
||||
{
|
||||
public class SearchManagerTest
|
||||
{
|
||||
[Fact]
|
||||
public void SearchTest()
|
||||
{
|
||||
FakeProductListingManager stubProductListingManager = new FakeProductListingManager();
|
||||
SearchManager searchManager = new SearchManager(stubProductListingManager);
|
||||
stubProductListingManager.RefreshProductListings();
|
||||
searchManager.Similarity = 0.8f;
|
||||
Assert.NotEmpty(searchManager.Search("Raspberry Pi").ToEnumerable());
|
||||
searchManager.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user