public async Task UpsertSingleQuoteData_ShouldThrowException_WhenSavingFailed() { _stockDataRepository.Setup(s => s.UpsertSingleQuoteData(It.IsAny <UpsertSingleQuoteData>())).Returns(Task.FromResult(false)); var query = new SingleQuoteQuery(1); var queryResult = new SingleQuoteQueryResult("MSFT", _singleQuoteData); await Assert.ThrowsAsync <ArgumentException>(async() => await _service.UpsertSingleQuoteData(query, queryResult)); }
/// <summary> /// Saves the single quote query result or updates it if it already exists. /// </summary> /// <param name="query"><see cref="SingleQuoteQuery"/> to upsert data for.</param> /// <param name="queryResult"><see cref="SingleQuoteQueryResult"/> stock data results to save.</param> /// <remarks> /// Will update the database and then <see cref="SingleQuoteCache"/> if it was successful. /// Error results will be ignored. /// </remarks> public async Task UpsertSingleQuoteData(SingleQuoteQuery query, SingleQuoteQueryResult queryResult) { if (queryResult.HasError) { return; } _logger.LogTrace("Query SymbolId {id} added to cache", query.SymbolId); const int primaryKeyViolationCode = 2627; try { bool successfulSave = await _stockDataRepository.UpsertSingleQuoteData(new UpsertSingleQuoteData(query.SymbolId, queryResult.Data)); _logger.LogTrace("Query SymbolId {id} saved to database", query.SymbolId); if (!successfulSave) { throw new ArgumentException($"query for symbolId {query.SymbolId} was not able to be updated"); } } catch (SqlException ex) when(ex.ErrorCode == primaryKeyViolationCode) { _logger.LogError("Query SymbolId {id} was duplicate insert in database", query.SymbolId); // Ignore the error since it means a race condition where we tried insert twice. // But that's fine since the stock data is unlikely to be different if it's that close in time. // This is more performant than adding locks as this case should be very exceptional. } // Only insert into cache if it successfully saved into database. _singleQuoteCache.Upsert(query.SymbolId, queryResult); }
/// <summary> /// Executes the query and saves the single quote data to the <see cref="SingleQuoteCache"/> and the database. /// </summary> public async Task SaveQueryResultToStore() { Symbol symbol = await _symbolRepository.GetSymbol(_query.SymbolId); _queryResult = await _stockClient.GetSingleQuoteData(_query, symbol.Ticker, symbol.ExchangeName); await _stockDataService.UpsertSingleQuoteData(_query, _queryResult); }
public async Task UpsertSingleQuoteData_ShouldNotUpsertSingleQuoteData_WhenQueryResultHasError() { _stockDataRepository.Setup(s => s.UpsertSingleQuoteData(It.IsAny <UpsertSingleQuoteData>())).Returns(Task.FromResult(true)); var query = new SingleQuoteQuery(1); var queryResult = new SingleQuoteQueryResult("error"); await _service.UpsertSingleQuoteData(query, queryResult); _stockDataRepository.Verify(s => s.UpsertSingleQuoteData(It.IsAny <UpsertSingleQuoteData>()), Times.Never); Assert.False(_cache.TryGet(query.SymbolId, out SingleQuoteQueryResult cachedResult)); }
public async Task GetSingleQuote_ShouldReturnErrorWhenUnknownSymbol() { var query = new SingleQuoteQuery(-1); var ticker = "AB1234567890"; var alphaVantageClient = new AlphaVantageClient(_mockHttpFactory, _mockAlphaVantageOptionsAccessor.Object, _parserFactory, _mockLogger.Object); SingleQuoteQueryResult singleQuoteResult = await alphaVantageClient.GetSingleQuoteData(query, ticker, "NYSE"); Assert.True(singleQuoteResult.HasError); Assert.False(string.IsNullOrEmpty(singleQuoteResult.ErrorMessage)); }
public async Task UpsertSingleQuoteData_ShouldUpsertSingleQuoteDataAndSaveIntoCache() { _stockDataRepository.Setup(s => s.UpsertSingleQuoteData(It.IsAny <UpsertSingleQuoteData>())).Returns(Task.FromResult(true)); var query = new SingleQuoteQuery(1); var queryResult = new SingleQuoteQueryResult("MSFT", _singleQuoteData); await _service.UpsertSingleQuoteData(query, queryResult); _stockDataRepository.Verify(s => s.UpsertSingleQuoteData(It.Is <UpsertSingleQuoteData>(u => u.SymbolId == query.SymbolId))); _cache.TryGet(query.SymbolId, out SingleQuoteQueryResult cachedResult); Assert.Equal(queryResult, cachedResult); }
public async Task GetSingleQuoteData_ShouldGetValueFromCache() { var query = new SingleQuoteQuery(1); var queryResult = new SingleQuoteQueryResult("MSFT", _singleQuoteData); _cache.Upsert(query.SymbolId, queryResult); StockSingleQuoteDataDTO data = await _service.GetSingleQuoteData(query.SymbolId); Assert.Equal(queryResult.Data, data.Data); _stockDataRepository.Verify(s => s.GetSingleQuoteData(It.IsAny <int>()), Times.Never); }
public async Task GetSingleQuoteData_ShouldGetValueFromDBAndSaveToCache_WhenNotInCache() { var query = new SingleQuoteQuery(1); var queryResult = new SingleQuoteQueryResult("MSFT", _singleQuoteData); _stockDataRepository.Setup(s => s.GetSingleQuoteData(It.IsAny <int>())).Returns(Task.FromResult(_singleQuoteData)); StockSingleQuoteDataDTO data = await _service.GetSingleQuoteData(query.SymbolId); Assert.Equal(queryResult.Data, data.Data); _stockDataRepository.Verify(s => s.GetSingleQuoteData(It.IsAny <int>()), Times.Once); _cache.TryGet(query.SymbolId, out SingleQuoteQueryResult cachedResult); Assert.Equal(queryResult.Data, cachedResult.Data); }
public async Task GetSingleQuote_ShouldReturnSingleQuoteStockData() { var query = new SingleQuoteQuery(-1); var ticker = "MSFT"; var alphaVantageClient = new AlphaVantageClient(_mockHttpFactory, _mockAlphaVantageOptionsAccessor.Object, _parserFactory, _mockLogger.Object); SingleQuoteQueryResult singleQuoteResult = await alphaVantageClient.GetSingleQuoteData(query, ticker, "NASDAQ"); Assert.False(singleQuoteResult.HasError); Assert.True(singleQuoteResult.Data.Low >= 0); Assert.True(singleQuoteResult.Data.High >= 0); Assert.True(singleQuoteResult.Data.Open >= 0); Assert.True(singleQuoteResult.Data.Volume >= 0); Assert.True(singleQuoteResult.Data.Price >= 0); Assert.True(singleQuoteResult.Data.PreviousClose >= 0); Assert.True(singleQuoteResult.Data.LastUpdated > new DateTime()); Assert.True(singleQuoteResult.Data.LastTradingDay > new DateTime()); Assert.Equal(ticker, singleQuoteResult.Data.Ticker); }