From 0ba4db83e0f9ad5a06b6104a393d89ac0f8e0250 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Sat, 22 Sep 2018 11:03:26 -0700 Subject: [PATCH 01/15] Handling confirmation updates correctly for early transactions. --- src/js/services/wallet-history.service.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/js/services/wallet-history.service.js b/src/js/services/wallet-history.service.js index 512a2d8b1..798c92671 100644 --- a/src/js/services/wallet-history.service.js +++ b/src/js/services/wallet-history.service.js @@ -28,8 +28,8 @@ function addEarlyTransactions(walletId, cachedTxs, newTxs) { var cachedTxIndexFromId = {}; - cachedTxs.forEach(function forCachedTx(tx){ - cachedTxIndexFromId[tx.txid] = true; + cachedTxs.forEach(function forCachedTx(tx, txIndex){ + cachedTxIndexFromId[tx.txid] = txIndex; }); var confirmationsUpdated = false; @@ -147,7 +147,7 @@ * @param {function(error, txs)} cb - txs is always an array, may be empty */ function getCachedTxHistory(walletId, cb) { - console.log('txhistory updateLocalTxHistoryByPage()'); + console.log('txhistory getCachedTxHistory()'); storageService.getTxHistory(walletId, function onGetTxHistory(err, txHistoryString){ if (err) { return cb(err, []); @@ -230,7 +230,7 @@ } function updateLocalTxHistoryByPage(wallet, getLatest, flushCacheOnNew, cb) { - console.log('txhistory updaetLocalTxHistoryByPage()'); + console.log('txhistory updateLocalTxHistoryByPage()'); if (flushCacheOnNew) { fetchTxHistoryByPage(wallet, 0, function onFetchTxHistory(err, txs){ if (err) { From a5a1d3edb673f589e17110deb55194a76ab170ab Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Sat, 22 Sep 2018 11:07:24 -0700 Subject: [PATCH 02/15] Remove debug logging. --- src/js/services/wallet-history.service.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/js/services/wallet-history.service.js b/src/js/services/wallet-history.service.js index 798c92671..5cb08e6ee 100644 --- a/src/js/services/wallet-history.service.js +++ b/src/js/services/wallet-history.service.js @@ -147,7 +147,6 @@ * @param {function(error, txs)} cb - txs is always an array, may be empty */ function getCachedTxHistory(walletId, cb) { - console.log('txhistory getCachedTxHistory()'); storageService.getTxHistory(walletId, function onGetTxHistory(err, txHistoryString){ if (err) { return cb(err, []); @@ -230,7 +229,6 @@ } function updateLocalTxHistoryByPage(wallet, getLatest, flushCacheOnNew, cb) { - console.log('txhistory updateLocalTxHistoryByPage()'); if (flushCacheOnNew) { fetchTxHistoryByPage(wallet, 0, function onFetchTxHistory(err, txs){ if (err) { From c661798cd14128a2266acb36786bd285685a6506 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Sat, 22 Sep 2018 17:45:19 -0700 Subject: [PATCH 03/15] Android Debug and release builds work when Gradle 3.3 is in PATH. --- Gruntfile.js | 2 +- app-template/config-template.xml | 2 +- src/android/build-extras.gradle | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 7968f2510..4ac23e47a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -71,7 +71,7 @@ module.exports = function(grunt) { sign_android: { // When the build log outputs "Built the following apk(s):", it seems to need the filename to start with "android-release". // It looks like it simply lists all apk files starting with "android-release" - command: 'rm -f platforms/android/build/outputs/apk/android-release-signed-*.apk; jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ../bitcoin-com-release-key.jks -signedjar platforms/android/build/outputs/apk/android-release-signed.apk platforms/android/build/outputs/apk/android-release-unsigned.apk bitcoin-com && zipalign -v 4 platforms/android/build/outputs/apk/android-release-signed.apk platforms/android/build/outputs/apk/bitcoin-com-wallet-<%= pkg.fullVersion %>-android-signed-aligned.apk', + command: 'rm -f platforms/android/build/outputs/apk/release/*-android-signed-aligned.apk; jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ../bitcoin-com-release-key.jks -signedjar platforms/android/build/outputs/apk/release/android-release-signed.apk platforms/android/build/outputs/apk/release/android-release-unsigned.apk bitcoin-com && zipalign -v 4 platforms/android/build/outputs/apk/release/android-release-signed.apk platforms/android/build/outputs/apk/release/bitcoin-com-wallet-<%= pkg.fullVersion %>-android-signed-aligned.apk', stdin: true, }, sign_desktop_dist: { diff --git a/app-template/config-template.xml b/app-template/config-template.xml index 8686b7b36..b24b86fae 100644 --- a/app-template/config-template.xml +++ b/app-template/config-template.xml @@ -77,7 +77,7 @@ - + diff --git a/src/android/build-extras.gradle b/src/android/build-extras.gradle index e7dd50572..c90145418 100644 --- a/src/android/build-extras.gradle +++ b/src/android/build-extras.gradle @@ -1,5 +1,6 @@ ext { ANDROID_SUPPORT_V4_VERSION = '26.1.0' + ANDROID_SUPPORT_ANNOTATIONS_VERSION = '26.1.0' } configurations.all { From 1b0541a7b5746c0ef2eae602695bc816cab1b0dc Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Sat, 22 Sep 2018 22:22:06 -0700 Subject: [PATCH 04/15] Return error from Shapeshift when pairs are unavailable. --- src/js/services/shapeShiftApiService.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/js/services/shapeShiftApiService.js b/src/js/services/shapeShiftApiService.js index cc5fb0792..92564464a 100644 --- a/src/js/services/shapeShiftApiService.js +++ b/src/js/services/shapeShiftApiService.js @@ -23,6 +23,13 @@ var ShapeShift = (function() { if (xmlhttp.status == 200) { var parsedResponse = JP(xmlhttp.responseText); cb.apply(null, [parsedResponse]); + } else if (xmlhttp.status === 500) { + var parsedResponse = JP(xmlhttp.responseText); + if (typeof parsedResponse.error === 'string') { + cb.apply(null, [parsedResponse]); + } else { + cb.apply(null, [new Error('Request Failed')]); + } } else { cb.apply(null, [new Error('Request Failed')]) } From 6452a0c7f4797a7321b58f4bff2ef72a54c01dda Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Sun, 23 Sep 2018 13:06:36 -0700 Subject: [PATCH 05/15] Handling JSON exception. --- src/js/services/shapeShiftApiService.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/js/services/shapeShiftApiService.js b/src/js/services/shapeShiftApiService.js index 92564464a..67e6f23de 100644 --- a/src/js/services/shapeShiftApiService.js +++ b/src/js/services/shapeShiftApiService.js @@ -23,15 +23,17 @@ var ShapeShift = (function() { if (xmlhttp.status == 200) { var parsedResponse = JP(xmlhttp.responseText); cb.apply(null, [parsedResponse]); - } else if (xmlhttp.status === 500) { - var parsedResponse = JP(xmlhttp.responseText); - if (typeof parsedResponse.error === 'string') { - cb.apply(null, [parsedResponse]); - } else { - cb.apply(null, [new Error('Request Failed')]); - } } else { - cb.apply(null, [new Error('Request Failed')]) + var cbResponse = new Error('Request Failed'); + if (xmlhttp.status === 500) { + try { + var errorResponse = JSON.parse(xmlhttp.responseText); + if (typeof errorResponse.error === 'string') { + cbResponse = errorResponse; + } + } catch (e) { /* nop */ } + } + cb.apply(null, [cbResponse]); } } }; From babdc8a13bb52474bd79d5433bc5a37f10293cd2 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Sun, 23 Sep 2018 20:14:42 -0700 Subject: [PATCH 06/15] Restored production setting for page size. --- src/js/services/wallet-history.service.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/services/wallet-history.service.js b/src/js/services/wallet-history.service.js index 5cb08e6ee..a0b36288d 100644 --- a/src/js/services/wallet-history.service.js +++ b/src/js/services/wallet-history.service.js @@ -7,8 +7,8 @@ .factory('walletHistoryService', walletHistoryService); function walletHistoryService(configService, storageService, lodash, $log, txFormatService) { - //var PAGE_SIZE = 50; - var PAGE_SIZE = 20; // For dev only + var PAGE_SIZE = 50; + //var PAGE_SIZE = 20; // For dev only // How much to overlap on each end of the page, for mitigating inconsistent sort order. var PAGE_OVERLAP_FRACTION = 0.2; var PAGE_OVERLAP = Math.floor(PAGE_SIZE * PAGE_OVERLAP_FRACTION); From 8f8027d573832c100e4293f9166bdd8a1cbb290a Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Sun, 23 Sep 2018 20:56:15 -0700 Subject: [PATCH 07/15] Reverse out bugfix. --- src/js/services/shapeShiftApiService.js | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/js/services/shapeShiftApiService.js b/src/js/services/shapeShiftApiService.js index 67e6f23de..a90e587d4 100644 --- a/src/js/services/shapeShiftApiService.js +++ b/src/js/services/shapeShiftApiService.js @@ -24,16 +24,7 @@ var ShapeShift = (function() { var parsedResponse = JP(xmlhttp.responseText); cb.apply(null, [parsedResponse]); } else { - var cbResponse = new Error('Request Failed'); - if (xmlhttp.status === 500) { - try { - var errorResponse = JSON.parse(xmlhttp.responseText); - if (typeof errorResponse.error === 'string') { - cbResponse = errorResponse; - } - } catch (e) { /* nop */ } - } - cb.apply(null, [cbResponse]); + cb.apply(null, [new Error('Request Failed')]); } } }; From d2178d670f2949f8c89164bdc7e94ed44ce31ecf Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Sun, 23 Sep 2018 21:05:26 -0700 Subject: [PATCH 08/15] Fix identification of BitPay. --- src/js/services/send-flow.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/services/send-flow.service.js b/src/js/services/send-flow.service.js index e8be2e487..babf5096a 100644 --- a/src/js/services/send-flow.service.js +++ b/src/js/services/send-flow.service.js @@ -52,7 +52,7 @@ angular // Detect some merchant that we know if (payProData.memo.indexOf('eGifter') > -1) { name = 'eGifter' - } else if (paymentUrl.indexOf('https://bitpay.com') > -1) { + } else if (payProData.url.indexOf('https://bitpay.com') > -1) { name = 'BitPay'; } From 5401bf9a0998d8515d21b195656568674ec67d8a Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Dominguez Date: Mon, 24 Sep 2018 16:54:40 +0200 Subject: [PATCH 09/15] Fix the case where the cache is empty --- src/js/services/wallet-history.service.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/js/services/wallet-history.service.js b/src/js/services/wallet-history.service.js index 5cb08e6ee..760f6994e 100644 --- a/src/js/services/wallet-history.service.js +++ b/src/js/services/wallet-history.service.js @@ -49,8 +49,9 @@ var overlappingTxFraction = overlappingTxsCount / Math.min(cachedTxs.length, PAGE_OVERLAP); console.log('overlappingTxFraction:', overlappingTxFraction); + console.log('overlappingTxsCount:', overlappingTxsCount); - if (overlappingTxFraction >= MIN_KNOWN_TX_OVERLAP_FRACTION) { // We are good + if (overlappingTxFraction >= MIN_KNOWN_TX_OVERLAP_FRACTION || (someTransactionsWereNew && overlappingTxsCount === 0)) { // We are good if (someTransactionsWereNew) { saveTxHistory(walletId, cachedTxs); } else if (confirmationsUpdated) { From fb41fca6015c7284657083139f8bc763437acfb6 Mon Sep 17 00:00:00 2001 From: Sebastiaan Pasma Date: Mon, 24 Sep 2018 17:13:28 +0200 Subject: [PATCH 10/15] Also apply fix to addLatestTransactions function --- src/js/services/wallet-history.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/services/wallet-history.service.js b/src/js/services/wallet-history.service.js index 01e752465..a9792c170 100644 --- a/src/js/services/wallet-history.service.js +++ b/src/js/services/wallet-history.service.js @@ -94,7 +94,7 @@ var overlappingTxFraction = overlappingTxsCount / Math.min(cachedTxs.length, PAGE_OVERLAP); - if (overlappingTxFraction >= MIN_KNOWN_TX_OVERLAP_FRACTION) { // We are good + if (overlappingTxFraction >= MIN_KNOWN_TX_OVERLAP_FRACTION || (someTransactionsWereNew && overlappingTxsCount === 0)) { // We are good if (someTransactionsWereNew) { var allTxs = uniqueNewTxs.concat(cachedTxs); saveTxHistory(walletId, allTxs); From d68870f7435d3ed9b40b1ef91026325051ecfbb3 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Wed, 26 Sep 2018 18:03:14 +1200 Subject: [PATCH 11/15] Bugfix for getting wallet history when cache is empty, while still enforcing overlap in transactions when cache contains transactions, to ensure no transactions are missed. --- src/js/services/wallet-history.service.js | 33 ++++++++++++++++------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/js/services/wallet-history.service.js b/src/js/services/wallet-history.service.js index a9792c170..f114a396d 100644 --- a/src/js/services/wallet-history.service.js +++ b/src/js/services/wallet-history.service.js @@ -6,7 +6,7 @@ .module('bitcoincom.services') .factory('walletHistoryService', walletHistoryService); - function walletHistoryService(configService, storageService, lodash, $log, txFormatService) { + function walletHistoryService(storageService, lodash, $log, txFormatService) { var PAGE_SIZE = 50; //var PAGE_SIZE = 20; // For dev only // How much to overlap on each end of the page, for mitigating inconsistent sort order. @@ -47,11 +47,17 @@ } }); - var overlappingTxFraction = overlappingTxsCount / Math.min(cachedTxs.length, PAGE_OVERLAP); - console.log('overlappingTxFraction:', overlappingTxFraction); - console.log('overlappingTxsCount:', overlappingTxsCount); - - if (overlappingTxFraction >= MIN_KNOWN_TX_OVERLAP_FRACTION || (someTransactionsWereNew && overlappingTxsCount === 0)) { // We are good + var txsAreContinuous = false; + if (cachedTxs.length > 0) { + var overlappingTxFraction = overlappingTxsCount / Math.min(cachedTxs.length, PAGE_OVERLAP); + console.log('overlappingTxsCount:', overlappingTxsCount); + console.log('overlappingTxFraction:', overlappingTxFraction); + txsAreContinuous = overlappingTxFraction >= MIN_KNOWN_TX_OVERLAP_FRACTION; + } else { + txsAreContinuous = true; + } + + if (txsAreContinuous) { if (someTransactionsWereNew) { saveTxHistory(walletId, cachedTxs); } else if (confirmationsUpdated) { @@ -62,7 +68,7 @@ return cachedTxs; } else { // We might be missing some txs. - console.error('We might be missing some txs in the history.'); + $log.error('We might be missing some txs in the history.'); // Our history is wrong, so remove it - we could instead, try to fetch data that was not so early. storageService.removeTxHistory(walletId, function onRemoveTxHistory(){}); return []; @@ -92,9 +98,17 @@ } }); - var overlappingTxFraction = overlappingTxsCount / Math.min(cachedTxs.length, PAGE_OVERLAP); + var txsAreContinuous = false; + if (cachedTxs.length > 0) { + var overlappingTxFraction = overlappingTxsCount / Math.min(cachedTxs.length, PAGE_OVERLAP); + console.log('overlappingTxsCount:', overlappingTxsCount); + console.log('overlappingTxFraction:', overlappingTxFraction); + txsAreContinuous = overlappingTxFraction >= MIN_KNOWN_TX_OVERLAP_FRACTION; + } else { + txsAreContinuous = true; + } - if (overlappingTxFraction >= MIN_KNOWN_TX_OVERLAP_FRACTION || (someTransactionsWereNew && overlappingTxsCount === 0)) { // We are good + if (txsAreContinuous) { if (someTransactionsWereNew) { var allTxs = uniqueNewTxs.concat(cachedTxs); saveTxHistory(walletId, allTxs); @@ -107,6 +121,7 @@ } } else { // We might be missing some txs. + $log.error('We might be missing some txs in the history.'); // Our history is wrong, so just include the latest ones saveTxHistory(walletId, newTxs); return newTxs; From 2d0e5c5f79f1e29747fb559556b7c5f55a133659 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Wed, 26 Sep 2018 18:24:24 +1200 Subject: [PATCH 12/15] Started on unit tests for wallet history. --- .../services/wallet-history.service.spec.js | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 src/js/services/wallet-history.service.spec.js diff --git a/src/js/services/wallet-history.service.spec.js b/src/js/services/wallet-history.service.spec.js new file mode 100644 index 000000000..1a04833f8 --- /dev/null +++ b/src/js/services/wallet-history.service.spec.js @@ -0,0 +1,81 @@ +fdescribe('walletHistoryService', function(){ + var history = []; + var historyStringFull; + var storageServiceMock; + var txFormatServiceMock; + var walletHistoryService; + + + beforeEach(function(){ + module('ngLodash'); + module('bitcoincom.services'); + + storageServiceMock = jasmine.createSpyObj(['getTxHistory', 'removeTxHistory', 'setTxHistory']); + txFormatServiceMock = jasmine.createSpyObj(['processTx']); + txFormatServiceMock.processTx.and.callFake(function(coin, tx){ + return tx; + }) + + module(function($provide) { + $provide.value('storageService', storageServiceMock); + $provide.value('txFormatService', txFormatServiceMock); + }); + + inject(function($injector){ + walletHistoryService = $injector.get('walletHistoryService'); + }); + + for(var i = 0; i < 100; i++) { + history.push({ + confirmations: i, + time: (Date.now() / 1000) - i, + txid: 'id' + i.toString() + }); + } + historyStringFull = JSON.stringify(history); + }); + + it('getCachedHistory empty', function() { + var returnedErr; + var returnedHistory; + var walletIdForStorageGet = ''; + + storageServiceMock.getTxHistory.and.callFake(function(walletId, cb){ + walletIdForStorageGet = walletId; + + cb(null, "[]"); + }); + + walletHistoryService.getCachedTxHistory('wallet1234', function(err, txHistory){ + returnedErr = err; + returnedHistory = txHistory; + }); + + expect(walletIdForStorageGet).toBe('wallet1234'); + expect(returnedErr).toBeNull(); + expect(returnedHistory.length).toBe(0); + }); + + it('getCachedHistory page full', function() { + var returnedErr; + var returnedHistory; + var walletIdForStorageGet = ''; + + storageServiceMock.getTxHistory.and.callFake(function(walletId, cb){ + walletIdForStorageGet = walletId; + + cb(null, JSON.stringify(history.slice(0, 50))); + }); + + walletHistoryService.getCachedTxHistory('wallet1234', function(err, txHistory){ + returnedErr = err; + returnedHistory = txHistory; + }); + + expect(walletIdForStorageGet).toBe('wallet1234'); + expect(returnedErr).toBeNull(); + expect(returnedHistory.length).toBe(50); + }); + + +}); \ No newline at end of file From 5825ff26b8a599bee96583962917f33a3fdacdf1 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Wed, 26 Sep 2018 21:50:42 +1200 Subject: [PATCH 13/15] A few more test cases. --- .../services/wallet-history.service.spec.js | 215 +++++++++++++++++- 1 file changed, 214 insertions(+), 1 deletion(-) diff --git a/src/js/services/wallet-history.service.spec.js b/src/js/services/wallet-history.service.spec.js index 1a04833f8..1f55ca031 100644 --- a/src/js/services/wallet-history.service.spec.js +++ b/src/js/services/wallet-history.service.spec.js @@ -3,6 +3,7 @@ fdescribe('walletHistoryService', function(){ var historyStringFull; var storageServiceMock; var txFormatServiceMock; + var walletMock; var walletHistoryService; @@ -14,7 +15,8 @@ fdescribe('walletHistoryService', function(){ txFormatServiceMock = jasmine.createSpyObj(['processTx']); txFormatServiceMock.processTx.and.callFake(function(coin, tx){ return tx; - }) + }); + walletMock = jasmine.createSpyObj(['getTxHistory']); module(function($provide) { $provide.value('storageService', storageServiceMock); @@ -56,6 +58,27 @@ fdescribe('walletHistoryService', function(){ expect(returnedHistory.length).toBe(0); }); + it('getCachedHistory error from storage', function() { + var returnedErr; + var returnedHistory; + var walletIdForStorageGet = ''; + + storageServiceMock.getTxHistory.and.callFake(function(walletId, cb){ + walletIdForStorageGet = walletId; + + cb(new Error('Something went wrong.'), null); + }); + + walletHistoryService.getCachedTxHistory('wallet12345', function(err, txHistory){ + returnedErr = err; + returnedHistory = txHistory; + }); + + expect(walletIdForStorageGet).toBe('wallet12345'); + expect(returnedErr.message).toBe('Something went wrong.'); + expect(returnedHistory.length).toBe(0); + }); + it('getCachedHistory page full', function() { var returnedErr; var returnedHistory; @@ -77,5 +100,195 @@ fdescribe('walletHistoryService', function(){ expect(returnedHistory.length).toBe(50); }); + it('updateLocalTxHistoryByPage, getEarlier, keep cache, sufficient overlap so saved.', function(){ + var fetchLimit; + var fetchSkip; + var returnedHistory; + var savedTxs; + var walletIdForStorageGet; + var walletIdForStorageSet; + walletMock.id = 'wallet67890'; + + storageServiceMock.getTxHistory.and.callFake(function(walletId, cb){ + walletIdForStorageGet = walletId; + + cb(null, JSON.stringify(history.slice(0, 40))); + }); + + walletMock.getTxHistory.and.callFake(function(opts, cb){ + fetchSkip = opts.skip; + fetchLimit = opts.limit; + + cb(null, history.slice(fetchSkip, fetchSkip + fetchLimit)); + }); + + storageServiceMock.setTxHistory.and.callFake(function(txs, walletId, cb){ + savedTxs = txs; + walletIdForStorageSet = walletId; + cb(null); + }); + + walletHistoryService.updateLocalTxHistoryByPage(walletMock, false, false, function(err, txs){ + returnedErr = err; + returnedHistory = txs; + }); + + expect(walletIdForStorageGet).toBe('wallet67890'); + expect(walletIdForStorageSet).toBe('wallet67890'); + expect(fetchSkip).toBe(30); + expect(fetchLimit).toBe(50); + expect(savedTxs.length).toBe(80); + expect(returnedErr).toBeNull(); + expect(returnedHistory.length).toBe(80); + }); + + it('updateLocalTxHistoryByPage, cache empty, getLatest, do not flush cache, some new so saved.', function(){ + var fetchLimit; + var fetchSkip; + var returnedHistory; + var savedTxs; + var walletIdForStorageGet; + var walletIdForStorageSet; + walletMock.id = 'wallet789'; + + storageServiceMock.getTxHistory.and.callFake(function(walletId, cb){ + walletIdForStorageGet = walletId; + cb(null, "[]"); + }); + + walletMock.getTxHistory.and.callFake(function(opts, cb){ + fetchSkip = opts.skip; + fetchLimit = opts.limit; + + cb(null, history.slice(0, 10)); + }); + + storageServiceMock.setTxHistory.and.callFake(function(txs, walletId, cb){ + savedTxs = txs; + walletIdForStorageSet = walletId; + cb(null); + }); + + walletHistoryService.updateLocalTxHistoryByPage(walletMock, true, false, function(err, txs){ + returnedErr = err; + returnedHistory = txs; + }); + + expect(walletIdForStorageGet).toBe('wallet789'); + expect(fetchSkip).toBe(0); + expect(fetchLimit).toBe(50); + expect(savedTxs.length).toBe(10); + expect(returnedErr).toBeNull(); + expect(returnedHistory.length).toBe(10); + }); + + it('updateLocalTxHistoryByPage, some cachedTx, getLatest, do not flush cache, nothing new so nothing added.', function(){ + var fetchLimit; + var fetchSkip; + var returnedHistory; + var walletIdForStorageGet; + walletMock.id = 'wallet789'; + + storageServiceMock.getTxHistory.and.callFake(function(walletId, cb){ + walletIdForStorageGet = walletId; + cb(null, JSON.stringify(history.slice(0, 40))); + }); + + walletMock.getTxHistory.and.callFake(function(opts, cb){ + fetchSkip = opts.skip; + fetchLimit = opts.limit; + + cb(null, []); + }); + + walletHistoryService.updateLocalTxHistoryByPage(walletMock, true, false, function(err, txs){ + returnedErr = err; + returnedHistory = txs; + }); + + expect(walletIdForStorageGet).toBe('wallet789'); + expect(fetchSkip).toBe(0); + expect(fetchLimit).toBe(50); + expect(returnedErr).toBeNull(); + expect(returnedHistory.length).toBe(40); + expect(storageServiceMock.setTxHistory.calls.any()).toBe(false); + }); + + it('updateLocalTxHistoryByPage, some cachedTx, getLatest, do not flush cache, some new with sufficient overlap so all saved.', function(){ + var fetchLimit; + var fetchSkip; + var returnedHistory; + var savedTxs; + var walletIdForStorageGet; + var walletIdForStorageSet; + walletMock.id = 'wallet789'; + + storageServiceMock.getTxHistory.and.callFake(function(walletId, cb){ + walletIdForStorageGet = walletId; + cb(null, JSON.stringify(history.slice(42, 72))); + }); + + walletMock.getTxHistory.and.callFake(function(opts, cb){ + fetchSkip = opts.skip; + fetchLimit = opts.limit; + + cb(null, history.slice(fetchSkip, fetchSkip + fetchLimit)); + }); + + storageServiceMock.setTxHistory.and.callFake(function(txs, walletId, cb){ + savedTxs = txs; + walletIdForStorageSet = walletId; + cb(null); + }); + + walletHistoryService.updateLocalTxHistoryByPage(walletMock, true, false, function(err, txs){ + returnedErr = err; + returnedHistory = txs; + }); + + expect(walletIdForStorageGet).toBe('wallet789'); + expect(fetchSkip).toBe(0); + expect(fetchLimit).toBe(50); + expect(walletIdForStorageSet).toBe('wallet789'); + expect(savedTxs.length).toBe(72); + expect(returnedErr).toBeNull(); + expect(returnedHistory.length).toBe(72); + + }); + + it('updateLocalTxHistoryByPage, getLatest, flush cache, some new so saved.', function(){ + var fetchLimit; + var fetchSkip; + var returnedHistory; + var savedTxs; + var walletIdForStorageSet; + walletMock.id = 'wallet7890'; + + walletMock.getTxHistory.and.callFake(function(opts, cb){ + fetchSkip = opts.skip; + fetchLimit = opts.limit; + + cb(null, history.slice(0, fetchLimit)); + }); + + storageServiceMock.setTxHistory.and.callFake(function(txs, walletId, cb){ + savedTxs = txs; + walletIdForStorageSet = walletId; + cb(null); + }); + + walletHistoryService.updateLocalTxHistoryByPage(walletMock, true, true, function(err, txs){ + returnedErr = err; + returnedHistory = txs; + }); + + expect(walletIdForStorageSet).toBe('wallet7890'); + expect(fetchSkip).toBe(0); + expect(fetchLimit).toBe(50); + expect(savedTxs.length).toBe(50); + expect(returnedErr).toBeNull(); + expect(returnedHistory.length).toBe(50); + expect(storageServiceMock.getTxHistory.calls.any()).toBe(false); + }); }); \ No newline at end of file From 9cfc05deddc7a66688141cf92a4308e01ba1cf79 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Wed, 26 Sep 2018 22:05:31 +1200 Subject: [PATCH 14/15] Unit test cases to cover confirmations increasing, and insufficient overlap. --- .../services/wallet-history.service.spec.js | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/src/js/services/wallet-history.service.spec.js b/src/js/services/wallet-history.service.spec.js index 1f55ca031..113ab34b3 100644 --- a/src/js/services/wallet-history.service.spec.js +++ b/src/js/services/wallet-history.service.spec.js @@ -214,6 +214,100 @@ fdescribe('walletHistoryService', function(){ expect(storageServiceMock.setTxHistory.calls.any()).toBe(false); }); + it('updateLocalTxHistoryByPage, some cachedTx, getLatest, do not flush cache, confirmations increased, saved.', function(){ + var fetchLimit; + var fetchSkip; + var returnedHistory; + var savedTxs; + var walletIdForStorageGet; + var walletIdForStorageSet; + walletMock.id = 'wallet789'; + + storageServiceMock.getTxHistory.and.callFake(function(walletId, cb){ + walletIdForStorageGet = walletId; + cb(null, JSON.stringify(history.slice(2, 52))); + }); + + walletMock.getTxHistory.and.callFake(function(opts, cb){ + fetchSkip = opts.skip; + fetchLimit = opts.limit; + + var historyWithHigherConfirmations = []; + for (var i = 0; i < 50; i++) { + historyWithHigherConfirmations.push({ + confirmations: i >= 6 ? history[i].confirmations : history[i].confirmations + 1, + time: history[i].time, + txid: history[i].txid + }); + } + + cb(null, historyWithHigherConfirmations.slice(fetchSkip, fetchSkip + fetchLimit)); + }); + + storageServiceMock.setTxHistory.and.callFake(function(txs, walletId, cb){ + savedTxs = txs; + walletIdForStorageSet = walletId; + cb(null); + }); + + walletHistoryService.updateLocalTxHistoryByPage(walletMock, true, false, function(err, txs){ + returnedErr = err; + returnedHistory = txs; + }); + + expect(walletIdForStorageGet).toBe('wallet789'); + expect(fetchSkip).toBe(0); + expect(fetchLimit).toBe(50); + expect(walletIdForStorageSet).toBe('wallet789'); + expect(savedTxs.length).toBe(52); + expect(returnedErr).toBeNull(); + expect(returnedHistory.length).toBe(52); + expect(returnedHistory[2].confirmations).toBe(3); + + }); + + it('updateLocalTxHistoryByPage, some cachedTx, getLatest, do not flush cache, some new with insufficient overlap, so only new saved.', function(){ + var fetchLimit; + var fetchSkip; + var returnedHistory; + var savedTxs; + var walletIdForStorageGet; + var walletIdForStorageSet; + walletMock.id = 'wallet789'; + + storageServiceMock.getTxHistory.and.callFake(function(walletId, cb){ + walletIdForStorageGet = walletId; + cb(null, JSON.stringify(history.slice(48, 78))); + }); + + walletMock.getTxHistory.and.callFake(function(opts, cb){ + fetchSkip = opts.skip; + fetchLimit = opts.limit; + + cb(null, history.slice(fetchSkip, fetchSkip + fetchLimit)); + }); + + storageServiceMock.setTxHistory.and.callFake(function(txs, walletId, cb){ + savedTxs = txs; + walletIdForStorageSet = walletId; + cb(null); + }); + + walletHistoryService.updateLocalTxHistoryByPage(walletMock, true, false, function(err, txs){ + returnedErr = err; + returnedHistory = txs; + }); + + expect(walletIdForStorageGet).toBe('wallet789'); + expect(fetchSkip).toBe(0); + expect(fetchLimit).toBe(50); + expect(walletIdForStorageSet).toBe('wallet789'); + expect(savedTxs.length).toBe(50); + expect(returnedErr).toBeNull(); + expect(returnedHistory.length).toBe(50); + + }); + it('updateLocalTxHistoryByPage, some cachedTx, getLatest, do not flush cache, some new with sufficient overlap so all saved.', function(){ var fetchLimit; var fetchSkip; From 4692e0d91d944b825c421a6fbd0ee148f0c2dd82 Mon Sep 17 00:00:00 2001 From: Brendon Duncan Date: Wed, 26 Sep 2018 22:38:29 +1200 Subject: [PATCH 15/15] Unit test case for 2 items in cache and that being all of the transactions. --- .../services/wallet-history.service.spec.js | 85 ++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/src/js/services/wallet-history.service.spec.js b/src/js/services/wallet-history.service.spec.js index 113ab34b3..a6d9e12a7 100644 --- a/src/js/services/wallet-history.service.spec.js +++ b/src/js/services/wallet-history.service.spec.js @@ -100,10 +100,49 @@ fdescribe('walletHistoryService', function(){ expect(returnedHistory.length).toBe(50); }); + it('updateLocalTxHistoryByPage, 2 in cache, getEarlier, keep cache, same 2 returned, so all transactions received.', function(){ + var fetchLimit; + var fetchSkip; + var returnedAllFetched; + var returnedErr; + var returnedHistory; + var walletIdForStorageGet; + walletMock.id = 'wallet456'; + + storageServiceMock.getTxHistory.and.callFake(function(walletId, cb){ + walletIdForStorageGet = walletId; + + cb(null, JSON.stringify(history.slice(0, 2))); + }); + + walletMock.getTxHistory.and.callFake(function(opts, cb){ + fetchSkip = opts.skip; + fetchLimit = opts.limit; + + cb(null, history.slice(0, 2)); + }); + + walletHistoryService.updateLocalTxHistoryByPage(walletMock, false, false, function(err, txs, allFetched){ + returnedErr = err; + returnedHistory = txs; + returnedAllFetched = allFetched; + }); + + expect(walletIdForStorageGet).toBe('wallet456'); + expect(fetchSkip).toBe(0); + expect(fetchLimit).toBe(50); + expect(returnedErr).toBeNull(); + expect(returnedHistory.length).toBe(2); + expect(returnedAllFetched).toBe(true); + expect(storageServiceMock.setTxHistory.calls.any()).toBe(false); + }); + it('updateLocalTxHistoryByPage, getEarlier, keep cache, sufficient overlap so saved.', function(){ var fetchLimit; var fetchSkip; + var returnedErr; var returnedHistory; + var returnedAllFetched; var savedTxs; var walletIdForStorageGet; var walletIdForStorageSet; @@ -128,9 +167,10 @@ fdescribe('walletHistoryService', function(){ cb(null); }); - walletHistoryService.updateLocalTxHistoryByPage(walletMock, false, false, function(err, txs){ + walletHistoryService.updateLocalTxHistoryByPage(walletMock, false, false, function(err, txs, allFetched){ returnedErr = err; returnedHistory = txs; + returnedAllFetched = allFetched; }); expect(walletIdForStorageGet).toBe('wallet67890'); @@ -140,6 +180,48 @@ fdescribe('walletHistoryService', function(){ expect(savedTxs.length).toBe(80); expect(returnedErr).toBeNull(); expect(returnedHistory.length).toBe(80); + expect(returnedAllFetched).toBe(false); + }); + + it('updateLocalTxHistoryByPage, cache empty, getLatest, do not flush cache, one new so saved.', function(){ + var fetchLimit; + var fetchSkip; + var returnedHistory; + var savedTxs; + var walletIdForStorageGet; + var walletIdForStorageSet; + walletMock.id = 'wallet789'; + + storageServiceMock.getTxHistory.and.callFake(function(walletId, cb){ + walletIdForStorageGet = walletId; + cb(null, "[]"); + }); + + walletMock.getTxHistory.and.callFake(function(opts, cb){ + fetchSkip = opts.skip; + fetchLimit = opts.limit; + + cb(null, history.slice(0, 1)); + }); + + storageServiceMock.setTxHistory.and.callFake(function(txs, walletId, cb){ + savedTxs = txs; + walletIdForStorageSet = walletId; + cb(null); + }); + + walletHistoryService.updateLocalTxHistoryByPage(walletMock, true, false, function(err, txs){ + returnedErr = err; + returnedHistory = txs; + }); + + expect(walletIdForStorageGet).toBe('wallet789'); + expect(fetchSkip).toBe(0); + expect(fetchLimit).toBe(50); + expect(savedTxs.length).toBe(1); + expect(walletIdForStorageSet).toBe('wallet789'); + expect(returnedErr).toBeNull(); + expect(returnedHistory.length).toBe(1); }); it('updateLocalTxHistoryByPage, cache empty, getLatest, do not flush cache, some new so saved.', function(){ @@ -178,6 +260,7 @@ fdescribe('walletHistoryService', function(){ expect(fetchSkip).toBe(0); expect(fetchLimit).toBe(50); expect(savedTxs.length).toBe(10); + expect(walletIdForStorageSet).toBe('wallet789'); expect(returnedErr).toBeNull(); expect(returnedHistory.length).toBe(10); });