Refactored repo organization. Added Jenkinsfile.

This commit is contained in:
2022-04-24 00:01:55 -05:00
parent 44e072a723
commit 9cc55e516d
36 changed files with 169 additions and 81 deletions

View 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);
}
}
}

View 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);
}
}
}

View File

@@ -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);
}
}
}

View 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();
}
}
}