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));
 }
Example #2
0
        /// <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);
        }
Example #3
0
        /// <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));
        }
Example #5
0
        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);
        }
Example #9
0
        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);
        }