@rabbitio/ui-kit 1.0.0-beta.41 → 1.0.0-beta.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitlab-ci.yml +29 -0
- package/.husky/commit-msg +8 -0
- package/.husky/pre-push +1 -0
- package/README.md +13 -4
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +6516 -0
- package/coverage/coverage-final.json +43 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +416 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/rabbit-ui-kit/index.html +116 -0
- package/coverage/rabbit-ui-kit/index.js.html +88 -0
- package/coverage/rabbit-ui-kit/src/common/adapters/axiosAdapter.js.html +190 -0
- package/coverage/rabbit-ui-kit/src/common/adapters/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/common/amountUtils.js.html +1393 -0
- package/coverage/rabbit-ui-kit/src/common/errorUtils.js.html +211 -0
- package/coverage/rabbit-ui-kit/src/common/external-apis/apiGroups.js.html +250 -0
- package/coverage/rabbit-ui-kit/src/common/external-apis/index.html +131 -0
- package/coverage/rabbit-ui-kit/src/common/external-apis/ipAddressProviders.js.html +499 -0
- package/coverage/rabbit-ui-kit/src/common/fiatCurrenciesService.js.html +568 -0
- package/coverage/rabbit-ui-kit/src/common/index.html +146 -0
- package/coverage/rabbit-ui-kit/src/common/models/blockchain.js.html +115 -0
- package/coverage/rabbit-ui-kit/src/common/models/coin.js.html +556 -0
- package/coverage/rabbit-ui-kit/src/common/models/index.html +146 -0
- package/coverage/rabbit-ui-kit/src/common/models/protocol.js.html +100 -0
- package/coverage/rabbit-ui-kit/src/common/utils/cache.js.html +889 -0
- package/coverage/rabbit-ui-kit/src/common/utils/emailAPI.js.html +139 -0
- package/coverage/rabbit-ui-kit/src/common/utils/index.html +161 -0
- package/coverage/rabbit-ui-kit/src/common/utils/logging/index.html +131 -0
- package/coverage/rabbit-ui-kit/src/common/utils/logging/logger.js.html +229 -0
- package/coverage/rabbit-ui-kit/src/common/utils/logging/logsStorage.js.html +268 -0
- package/coverage/rabbit-ui-kit/src/common/utils/postponeExecution.js.html +118 -0
- package/coverage/rabbit-ui-kit/src/common/utils/safeStringify.js.html +235 -0
- package/coverage/rabbit-ui-kit/src/components/atoms/AssetIcon/AssetIcon.jsx.html +250 -0
- package/coverage/rabbit-ui-kit/src/components/atoms/AssetIcon/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/components/atoms/LoadingDots/LoadingDots.jsx.html +256 -0
- package/coverage/rabbit-ui-kit/src/components/atoms/LoadingDots/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/components/atoms/SupportChat/SupportChat.jsx.html +229 -0
- package/coverage/rabbit-ui-kit/src/components/atoms/SupportChat/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/components/atoms/buttons/Button/Button.jsx.html +802 -0
- package/coverage/rabbit-ui-kit/src/components/atoms/buttons/Button/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/components/hooks/index.html +131 -0
- package/coverage/rabbit-ui-kit/src/components/hooks/useCallHandlingErrors.js.html +163 -0
- package/coverage/rabbit-ui-kit/src/components/hooks/useReferredState.js.html +157 -0
- package/coverage/rabbit-ui-kit/src/components/utils/index.html +146 -0
- package/coverage/rabbit-ui-kit/src/components/utils/inputValueProviders.js.html +259 -0
- package/coverage/rabbit-ui-kit/src/components/utils/uiUtils.js.html +127 -0
- package/coverage/rabbit-ui-kit/src/components/utils/urlQueryUtils.js.html +346 -0
- package/coverage/rabbit-ui-kit/src/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/index.js.html +250 -0
- package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/cacheAndConcurrentRequestsResolver.js.html +1762 -0
- package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/cachedRobustExternalApiCallerService.js.html +649 -0
- package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/cancelProcessing.js.html +172 -0
- package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/concurrentCalculationsMetadataHolder.js.html +394 -0
- package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/externalApiProvider.js.html +553 -0
- package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/externalServicesStatsCollector.js.html +331 -0
- package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/index.html +206 -0
- package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/robustExternalAPICallerService.js.html +1249 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/index.html +131 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/swapProvider.js.html +727 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/swapspaceSwapProvider.js.html +2899 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/models/baseSwapCreationInfo.js.html +214 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/models/existingSwap.js.html +304 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/models/existingSwapWithFiatData.js.html +487 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/models/index.html +146 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/services/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/services/publicSwapService.js.html +2191 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/utils/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/utils/swapUtils.js.html +742 -0
- package/coverage/rabbit-ui-kit/stories/atoms/LoadingDots.stories.jsx.html +226 -0
- package/coverage/rabbit-ui-kit/stories/atoms/buttons/Button.stories.jsx.html +946 -0
- package/coverage/rabbit-ui-kit/stories/atoms/buttons/index.html +116 -0
- package/coverage/rabbit-ui-kit/stories/atoms/index.html +116 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +196 -0
- package/dist/index.cjs +1706 -1498
- package/dist/index.cjs.map +1 -1
- package/dist/index.modern.js +817 -666
- package/dist/index.modern.js.map +1 -1
- package/dist/index.module.js +1704 -1498
- package/dist/index.module.js.map +1 -1
- package/dist/index.umd.js +1664 -1456
- package/dist/index.umd.js.map +1 -1
- package/package.json +11 -3
- package/src/common/amountUtils.js +4 -2
- package/src/common/external-apis/ipAddressProviders.js +138 -0
- package/src/common/tests/integration/external-apis/ipAddressProviders/getClientIpAddress.test.js +14 -0
- package/src/common/utils/cache.js +4 -4
- package/src/components/tests/utils/inputValueProviders/provideFormatOfFloatValueByInputString.test.js +139 -0
- package/src/components/tests/utils/urlQueryUtils/getQueryParameterValues.test.js +71 -0
- package/src/components/tests/utils/urlQueryUtils/saveQueryParameterAndValues.test.js +144 -0
- package/src/components/utils/inputValueProviders.js +58 -0
- package/src/index.js +2 -0
- package/src/robustExteranlApiCallerService/robustExternalAPICallerService.js +4 -2
- package/src/robustExteranlApiCallerService/tests/robustExternalAPICallerService/robustExternalAPICallerService/callExternalAPI/_performCallAttempt.test.js +787 -0
- package/src/robustExteranlApiCallerService/tests/robustExternalAPICallerService/robustExternalAPICallerService/callExternalAPI/callExternalAPI.test.js +745 -0
- package/src/robustExteranlApiCallerService/tests/robustExternalAPICallerService/robustExternalAPICallerService/constructor.test.js +31 -0
- package/src/swaps-lib/external-apis/swapProvider.js +17 -4
- package/src/swaps-lib/external-apis/swapspaceSwapProvider.js +91 -30
- package/src/swaps-lib/models/baseSwapCreationInfo.js +4 -1
- package/src/swaps-lib/models/existingSwap.js +3 -0
- package/src/swaps-lib/models/existingSwapWithFiatData.js +4 -0
- package/src/swaps-lib/services/publicSwapService.js +32 -4
- package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/_fetchSupportedCurrenciesIfNeeded.test.js +506 -0
- package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/createSwap.test.js +1311 -0
- package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getAllSupportedCurrencies.test.js +76 -0
- package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getDepositCurrencies.test.js +82 -0
- package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getSwapInfo.test.js +1892 -0
- package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getWithdrawalCurrencies.test.js +111 -0
- package/src/swaps-lib/test/utils/swapUtils/safeHandleRequestsLimitExceeding.test.js +88 -0
|
@@ -0,0 +1,745 @@
|
|
|
1
|
+
import sinon from "sinon";
|
|
2
|
+
import should from "should";
|
|
3
|
+
|
|
4
|
+
import { beforeEach, afterEach, describe, it } from "vitest";
|
|
5
|
+
|
|
6
|
+
import { v4 } from "uuid";
|
|
7
|
+
import { ExternalApiProvider } from "../../../../externalApiProvider.js";
|
|
8
|
+
import { ApiGroup } from "../../../../../common/external-apis/apiGroups.js";
|
|
9
|
+
import { RobustExternalAPICallerService } from "../../../../robustExternalAPICallerService.js";
|
|
10
|
+
|
|
11
|
+
describe("RobustExternalAPICallerService", function () {
|
|
12
|
+
describe("#callExternalAPI", function () {
|
|
13
|
+
const generateProviders = (
|
|
14
|
+
count,
|
|
15
|
+
endpoints = "any",
|
|
16
|
+
httpMethods = "any",
|
|
17
|
+
getDataByResponseFunctions = "any",
|
|
18
|
+
RPSes = null,
|
|
19
|
+
timeouts = null
|
|
20
|
+
) => {
|
|
21
|
+
const providers = [];
|
|
22
|
+
const composeQueryStringStubs = [];
|
|
23
|
+
for (let i = 0; i < count; ++i) {
|
|
24
|
+
class TempProvider extends ExternalApiProvider {
|
|
25
|
+
constructor() {
|
|
26
|
+
super(
|
|
27
|
+
endpoints === "any" ? "any" : endpoints[i],
|
|
28
|
+
httpMethods === "any" ? "get" : httpMethods[i],
|
|
29
|
+
timeouts ? timeouts[i] : null,
|
|
30
|
+
RPSes === null
|
|
31
|
+
? new ApiGroup(v4(), 10)
|
|
32
|
+
: new ApiGroup(v4(), RPSes[i])
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
getDataByResponse(
|
|
36
|
+
response,
|
|
37
|
+
params = [],
|
|
38
|
+
subRequestIndex = 0,
|
|
39
|
+
iterationsData = []
|
|
40
|
+
) {
|
|
41
|
+
const func =
|
|
42
|
+
getDataByResponseFunctions === "any"
|
|
43
|
+
? "any"
|
|
44
|
+
: Array.isArray(getDataByResponseFunctions[i])
|
|
45
|
+
? getDataByResponseFunctions[i][
|
|
46
|
+
subRequestIndex
|
|
47
|
+
]
|
|
48
|
+
: getDataByResponseFunctions[i];
|
|
49
|
+
return func();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const provider = new TempProvider();
|
|
53
|
+
providers.push(provider);
|
|
54
|
+
const composeQueryStringStub = sinon.stub(
|
|
55
|
+
provider,
|
|
56
|
+
"composeQueryString"
|
|
57
|
+
);
|
|
58
|
+
composeQueryStringStubs.push(composeQueryStringStub);
|
|
59
|
+
}
|
|
60
|
+
const isRpsExceededStubs = [];
|
|
61
|
+
providers.forEach((provider) => {
|
|
62
|
+
if (
|
|
63
|
+
provider.httpMethod === "post" ||
|
|
64
|
+
provider.httpMethod === "put" ||
|
|
65
|
+
provider.httpMethod === "patch"
|
|
66
|
+
) {
|
|
67
|
+
provider.composeBody = () => {};
|
|
68
|
+
sinon.stub(provider, "composeBody");
|
|
69
|
+
}
|
|
70
|
+
const isRPSExceededStub = sinon.stub(provider, "isRpsExceeded");
|
|
71
|
+
isRPSExceededStub.returns(false);
|
|
72
|
+
isRpsExceededStubs.push(isRPSExceededStub);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return { providers, isRpsExceededStubs, composeQueryStringStubs };
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const anyTimeout = 1000;
|
|
79
|
+
const anyData = "any data";
|
|
80
|
+
|
|
81
|
+
let setTimeoutBackup = null;
|
|
82
|
+
beforeEach(function () {
|
|
83
|
+
setTimeoutBackup = global.setTimeout;
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
afterEach(function () {
|
|
87
|
+
global.setTimeout = setTimeoutBackup;
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("Should perform n+1 attempts when first n requests return null and n+1's returns not-null data and n is less than max_attempts_count", async function () {
|
|
91
|
+
const retrieverService = new RobustExternalAPICallerService(
|
|
92
|
+
"testService",
|
|
93
|
+
generateProviders(4).providers,
|
|
94
|
+
// eslint-disable-next-line no-console
|
|
95
|
+
console.log
|
|
96
|
+
);
|
|
97
|
+
const attemptsCount = 6;
|
|
98
|
+
const failingAttemptsCount = Math.floor(attemptsCount * 0.6);
|
|
99
|
+
const _performCallAttemptStub = sinon.stub(
|
|
100
|
+
retrieverService,
|
|
101
|
+
"_performCallAttempt"
|
|
102
|
+
);
|
|
103
|
+
for (let i = 0; i < failingAttemptsCount; ++i) {
|
|
104
|
+
_performCallAttemptStub.onCall(i).resolves({
|
|
105
|
+
data: null,
|
|
106
|
+
shouldBeForceRetried: false,
|
|
107
|
+
errors: [],
|
|
108
|
+
rpsFactor: RobustExternalAPICallerService.defaultRPSFactor,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
_performCallAttemptStub.onCall(failingAttemptsCount).resolves({
|
|
112
|
+
data: "some data",
|
|
113
|
+
shouldBeForceRetried: false,
|
|
114
|
+
errors: [],
|
|
115
|
+
rpsFactor: RobustExternalAPICallerService.defaultRPSFactor,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
await retrieverService.callExternalAPI(
|
|
119
|
+
[],
|
|
120
|
+
anyTimeout,
|
|
121
|
+
null,
|
|
122
|
+
attemptsCount
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
_performCallAttemptStub.callCount.should.be.equal(
|
|
126
|
+
failingAttemptsCount + 1
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("Should perform max_attempts_count due to null data and shouldBeForceRetried is false for the last call", async function () {
|
|
131
|
+
const retrieverService = new RobustExternalAPICallerService(
|
|
132
|
+
"testService",
|
|
133
|
+
generateProviders(4).providers,
|
|
134
|
+
// eslint-disable-next-line no-console
|
|
135
|
+
console.log
|
|
136
|
+
);
|
|
137
|
+
const attemptsCount = 5;
|
|
138
|
+
const _performCallAttemptStub = sinon.stub(
|
|
139
|
+
retrieverService,
|
|
140
|
+
"_performCallAttempt"
|
|
141
|
+
);
|
|
142
|
+
for (let i = 0; i < attemptsCount; ++i) {
|
|
143
|
+
_performCallAttemptStub.onCall(i).resolves({
|
|
144
|
+
data: null,
|
|
145
|
+
shouldBeForceRetried: false,
|
|
146
|
+
errors: [],
|
|
147
|
+
rpsFactor: RobustExternalAPICallerService.defaultRPSFactor,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
await retrieverService.callExternalAPI(
|
|
153
|
+
[],
|
|
154
|
+
anyTimeout,
|
|
155
|
+
null,
|
|
156
|
+
attemptsCount
|
|
157
|
+
);
|
|
158
|
+
} catch (e) {
|
|
159
|
+
// We expect an error here
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
_performCallAttemptStub.callCount.should.be.equal(attemptsCount);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("Should perform max_attempts_count + n requests when all attempts return null data and shouldBeForceRetried is true for max_attempts_count-1 request and for n more requests", async function () {
|
|
166
|
+
const retrieverService = new RobustExternalAPICallerService(
|
|
167
|
+
"testService",
|
|
168
|
+
generateProviders(4).providers,
|
|
169
|
+
// eslint-disable-next-line no-console
|
|
170
|
+
console.log
|
|
171
|
+
);
|
|
172
|
+
const attemptsCount = 5;
|
|
173
|
+
const countOfAdditionalRequestsDueToForceRetryNeed = 3;
|
|
174
|
+
const _performCallAttemptStub = sinon.stub(
|
|
175
|
+
retrieverService,
|
|
176
|
+
"_performCallAttempt"
|
|
177
|
+
);
|
|
178
|
+
for (
|
|
179
|
+
let i = 0;
|
|
180
|
+
i <
|
|
181
|
+
attemptsCount + countOfAdditionalRequestsDueToForceRetryNeed;
|
|
182
|
+
++i
|
|
183
|
+
) {
|
|
184
|
+
_performCallAttemptStub.onCall(i).resolves({
|
|
185
|
+
data: null,
|
|
186
|
+
shouldBeForceRetried:
|
|
187
|
+
i >= attemptsCount - 1 &&
|
|
188
|
+
i !==
|
|
189
|
+
attemptsCount +
|
|
190
|
+
countOfAdditionalRequestsDueToForceRetryNeed -
|
|
191
|
+
1,
|
|
192
|
+
errors: [],
|
|
193
|
+
rpsFactor: RobustExternalAPICallerService.defaultRPSFactor,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
await retrieverService.callExternalAPI(
|
|
199
|
+
[],
|
|
200
|
+
anyTimeout,
|
|
201
|
+
null,
|
|
202
|
+
attemptsCount
|
|
203
|
+
);
|
|
204
|
+
} catch (e) {
|
|
205
|
+
// We expect an error here
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
_performCallAttemptStub.callCount.should.be.equal(
|
|
209
|
+
attemptsCount + countOfAdditionalRequestsDueToForceRetryNeed
|
|
210
|
+
);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it("Should return null if all requests return null if doNotFailForNowData is true", async function () {
|
|
214
|
+
const retrieverService = new RobustExternalAPICallerService(
|
|
215
|
+
"testService",
|
|
216
|
+
generateProviders(4).providers,
|
|
217
|
+
// eslint-disable-next-line no-console
|
|
218
|
+
console.log
|
|
219
|
+
);
|
|
220
|
+
const attemptsCount = 5;
|
|
221
|
+
const _performCallAttemptStub = sinon.stub(
|
|
222
|
+
retrieverService,
|
|
223
|
+
"_performCallAttempt"
|
|
224
|
+
);
|
|
225
|
+
for (let i = 0; i < attemptsCount; ++i) {
|
|
226
|
+
_performCallAttemptStub.onCall(i).resolves({
|
|
227
|
+
data: null,
|
|
228
|
+
shouldBeForceRetried: false,
|
|
229
|
+
errors: [],
|
|
230
|
+
rpsFactor: RobustExternalAPICallerService.defaultRPSFactor,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const result = await retrieverService.callExternalAPI(
|
|
235
|
+
[],
|
|
236
|
+
anyTimeout,
|
|
237
|
+
null,
|
|
238
|
+
attemptsCount,
|
|
239
|
+
true
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
(result == null).should.be.true();
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it("Should throw an error if all requests return null if doNotFailForNowData is false", async function () {
|
|
246
|
+
const retrieverService = new RobustExternalAPICallerService(
|
|
247
|
+
"testService",
|
|
248
|
+
generateProviders(4).providers,
|
|
249
|
+
// eslint-disable-next-line no-console
|
|
250
|
+
console.log
|
|
251
|
+
);
|
|
252
|
+
const attemptsCount = 5;
|
|
253
|
+
const _performCallAttemptStub = sinon.stub(
|
|
254
|
+
retrieverService,
|
|
255
|
+
"_performCallAttempt"
|
|
256
|
+
);
|
|
257
|
+
for (let i = 0; i < attemptsCount; ++i) {
|
|
258
|
+
_performCallAttemptStub.onCall(i).resolves({
|
|
259
|
+
data: null,
|
|
260
|
+
shouldBeForceRetried: false,
|
|
261
|
+
errors: [],
|
|
262
|
+
rpsFactor: RobustExternalAPICallerService.defaultRPSFactor,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
await retrieverService.callExternalAPI(
|
|
268
|
+
[],
|
|
269
|
+
anyTimeout,
|
|
270
|
+
null,
|
|
271
|
+
attemptsCount
|
|
272
|
+
);
|
|
273
|
+
} catch (e) {
|
|
274
|
+
e.message.should.match(
|
|
275
|
+
/.*Failed to retrieve data. It means all attempts have been failed.*/
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it("Should use rpsFactor = 1 by default (as a parameter of the first call to _performCallAttempt)", async function () {
|
|
281
|
+
const retrieverService = new RobustExternalAPICallerService(
|
|
282
|
+
"testService",
|
|
283
|
+
generateProviders(4).providers,
|
|
284
|
+
// eslint-disable-next-line no-console
|
|
285
|
+
console.log
|
|
286
|
+
);
|
|
287
|
+
const attemptsCount = 1;
|
|
288
|
+
const _performCallAttemptStub = sinon.stub(
|
|
289
|
+
retrieverService,
|
|
290
|
+
"_performCallAttempt"
|
|
291
|
+
);
|
|
292
|
+
_performCallAttemptStub.onCall(0).resolves({
|
|
293
|
+
data: anyData,
|
|
294
|
+
shouldBeForceRetried: false,
|
|
295
|
+
errors: [],
|
|
296
|
+
rpsFactor: RobustExternalAPICallerService.defaultRPSFactor,
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
await retrieverService.callExternalAPI(
|
|
300
|
+
[],
|
|
301
|
+
anyTimeout,
|
|
302
|
+
null,
|
|
303
|
+
attemptsCount
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
_performCallAttemptStub.args[0][3].should.be.equal(1);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it("Should call _performCallAttempt without the delay when there is a first attempt", async function () {
|
|
310
|
+
const retrieverService = new RobustExternalAPICallerService(
|
|
311
|
+
"testService",
|
|
312
|
+
generateProviders(4).providers,
|
|
313
|
+
// eslint-disable-next-line no-console
|
|
314
|
+
console.log
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
global.setTimeout = sinon.stub();
|
|
318
|
+
|
|
319
|
+
const attemptsCount = 1;
|
|
320
|
+
const _performCallAttemptStub = sinon.stub(
|
|
321
|
+
retrieverService,
|
|
322
|
+
"_performCallAttempt"
|
|
323
|
+
);
|
|
324
|
+
_performCallAttemptStub.onCall(0).resolves({
|
|
325
|
+
data: anyData,
|
|
326
|
+
shouldBeForceRetried: false,
|
|
327
|
+
errors: [],
|
|
328
|
+
rpsFactor: RobustExternalAPICallerService.defaultRPSFactor,
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
await retrieverService.callExternalAPI(
|
|
332
|
+
[],
|
|
333
|
+
anyTimeout,
|
|
334
|
+
null,
|
|
335
|
+
attemptsCount
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
setTimeout.callCount.should.be.equal(0);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it("Should call _performCallAttempt with delay n-1 times when there are n attempts performed", async function () {
|
|
342
|
+
const retrieverService = new RobustExternalAPICallerService(
|
|
343
|
+
"testService",
|
|
344
|
+
generateProviders(4).providers,
|
|
345
|
+
// eslint-disable-next-line no-console
|
|
346
|
+
console.log
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
sinon.spy(global, "setTimeout");
|
|
350
|
+
|
|
351
|
+
const attemptsCount = 4;
|
|
352
|
+
const failingAttemptsCount = 2;
|
|
353
|
+
const _performCallAttemptStub = sinon.stub(
|
|
354
|
+
retrieverService,
|
|
355
|
+
"_performCallAttempt"
|
|
356
|
+
);
|
|
357
|
+
for (let i = 0; i <= failingAttemptsCount; ++i) {
|
|
358
|
+
_performCallAttemptStub.onCall(i).resolves({
|
|
359
|
+
data: i === failingAttemptsCount ? anyData : null,
|
|
360
|
+
shouldBeForceRetried: false,
|
|
361
|
+
errors: [],
|
|
362
|
+
rpsFactor: RobustExternalAPICallerService.defaultRPSFactor,
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
await retrieverService.callExternalAPI(
|
|
367
|
+
[],
|
|
368
|
+
anyTimeout,
|
|
369
|
+
null,
|
|
370
|
+
attemptsCount
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
setTimeout.callCount.should.be.equal(failingAttemptsCount);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it("Should call _performCallAttempt with delay corresponding to the max rps and default rpsFactor", async function () {
|
|
377
|
+
const RPSes = [10, 20, 4, 15];
|
|
378
|
+
const retrieverService = new RobustExternalAPICallerService(
|
|
379
|
+
"testService",
|
|
380
|
+
generateProviders(4, "any", "any", "any", RPSes).providers,
|
|
381
|
+
// eslint-disable-next-line no-console
|
|
382
|
+
console.log
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
sinon.spy(global, "setTimeout");
|
|
386
|
+
|
|
387
|
+
const attemptsCount = 5;
|
|
388
|
+
const failingAttemptsCount = 3;
|
|
389
|
+
const _performCallAttemptStub = sinon.stub(
|
|
390
|
+
retrieverService,
|
|
391
|
+
"_performCallAttempt"
|
|
392
|
+
);
|
|
393
|
+
for (let i = 0; i <= failingAttemptsCount; ++i) {
|
|
394
|
+
_performCallAttemptStub.onCall(i).resolves({
|
|
395
|
+
data: i === failingAttemptsCount ? anyData : null,
|
|
396
|
+
shouldBeForceRetried: false,
|
|
397
|
+
errors: [],
|
|
398
|
+
rpsFactor: RobustExternalAPICallerService.defaultRPSFactor,
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
await retrieverService.callExternalAPI(
|
|
403
|
+
[],
|
|
404
|
+
anyTimeout,
|
|
405
|
+
null,
|
|
406
|
+
attemptsCount
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
for (let j = 0; j < failingAttemptsCount; ++j) {
|
|
410
|
+
setTimeout.args[j][1].should.be.equal(
|
|
411
|
+
1000 /
|
|
412
|
+
(Math.max(...RPSes) /
|
|
413
|
+
RobustExternalAPICallerService.defaultRPSFactor)
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
it("Should call _performCallAttempt with delay corresponding to the max rps and increasing rpsFactor", async function () {
|
|
419
|
+
const RPSes = [1, 11, 39, 0.1];
|
|
420
|
+
const retrieverService = new RobustExternalAPICallerService(
|
|
421
|
+
"testService",
|
|
422
|
+
generateProviders(4, "any", "any", "any", RPSes).providers,
|
|
423
|
+
// eslint-disable-next-line no-console
|
|
424
|
+
console.log
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
sinon.spy(global, "setTimeout");
|
|
428
|
+
|
|
429
|
+
const attemptsCount = 5;
|
|
430
|
+
const failingAttemptsCount = 3;
|
|
431
|
+
const _performCallAttemptStub = sinon.stub(
|
|
432
|
+
retrieverService,
|
|
433
|
+
"_performCallAttempt"
|
|
434
|
+
);
|
|
435
|
+
const rpsFactors = new Array(4)
|
|
436
|
+
.fill(RobustExternalAPICallerService.defaultRPSFactor)
|
|
437
|
+
.map(
|
|
438
|
+
(factor, index) =>
|
|
439
|
+
factor *
|
|
440
|
+
Math.pow(
|
|
441
|
+
RobustExternalAPICallerService.rpsMultiplier,
|
|
442
|
+
index
|
|
443
|
+
)
|
|
444
|
+
);
|
|
445
|
+
|
|
446
|
+
for (let i = 0; i <= failingAttemptsCount; ++i) {
|
|
447
|
+
_performCallAttemptStub.onCall(i).resolves({
|
|
448
|
+
data: i === failingAttemptsCount ? anyData : null,
|
|
449
|
+
shouldBeForceRetried: false,
|
|
450
|
+
errors: [],
|
|
451
|
+
rpsFactor: rpsFactors[i],
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
await retrieverService.callExternalAPI(
|
|
456
|
+
[],
|
|
457
|
+
anyTimeout,
|
|
458
|
+
null,
|
|
459
|
+
attemptsCount
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
for (let j = 0; j < failingAttemptsCount; ++j) {
|
|
463
|
+
setTimeout.args[j][1].should.be.equal(
|
|
464
|
+
1000 / (Math.max(...RPSes) / rpsFactors[j]),
|
|
465
|
+
`Attempt ${j} failed`
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
it("Should log the errors array returned by _performCallAttempt", async function () {
|
|
471
|
+
const retrieverService = new RobustExternalAPICallerService(
|
|
472
|
+
"testService",
|
|
473
|
+
generateProviders(4).providers
|
|
474
|
+
);
|
|
475
|
+
|
|
476
|
+
const spy = sinon.spy(retrieverService, "_logger");
|
|
477
|
+
|
|
478
|
+
const attemptsCount = 3;
|
|
479
|
+
const failingAttemptsCount = 2;
|
|
480
|
+
const _performCallAttemptStub = sinon.stub(
|
|
481
|
+
retrieverService,
|
|
482
|
+
"_performCallAttempt"
|
|
483
|
+
);
|
|
484
|
+
for (let i = 0; i <= failingAttemptsCount; ++i) {
|
|
485
|
+
_performCallAttemptStub.onCall(i).resolves({
|
|
486
|
+
data: i === failingAttemptsCount ? anyData : null,
|
|
487
|
+
shouldBeForceRetried: false,
|
|
488
|
+
errors:
|
|
489
|
+
i !== failingAttemptsCount
|
|
490
|
+
? [`aaa${i}${i}${i}`, `bbb${i}${i}${i}`]
|
|
491
|
+
: [],
|
|
492
|
+
rpsFactor: RobustExternalAPICallerService.defaultRPSFactor,
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
await retrieverService.callExternalAPI(
|
|
497
|
+
[],
|
|
498
|
+
anyTimeout,
|
|
499
|
+
null,
|
|
500
|
+
attemptsCount,
|
|
501
|
+
true
|
|
502
|
+
);
|
|
503
|
+
|
|
504
|
+
for (let j = 0; j < failingAttemptsCount; ++j) {
|
|
505
|
+
spy.args[j][0].message
|
|
506
|
+
.includes(`aaa${j}${j}${j}`)
|
|
507
|
+
.should.be.true();
|
|
508
|
+
spy.args[j][0].message
|
|
509
|
+
.includes(`bbb${j}${j}${j}`)
|
|
510
|
+
.should.be.true();
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
it("Should log an unexpected error occurred during the _performCallAttempt call", async function () {
|
|
515
|
+
const retrieverService = new RobustExternalAPICallerService(
|
|
516
|
+
"testService",
|
|
517
|
+
generateProviders(4).providers
|
|
518
|
+
);
|
|
519
|
+
|
|
520
|
+
const spy = sinon.spy(retrieverService, "_logger");
|
|
521
|
+
|
|
522
|
+
const someError = new Error("Failed ### in tests");
|
|
523
|
+
const attemptsCount = 1;
|
|
524
|
+
const _performCallAttemptStub = sinon.stub(
|
|
525
|
+
retrieverService,
|
|
526
|
+
"_performCallAttempt"
|
|
527
|
+
);
|
|
528
|
+
_performCallAttemptStub.onCall(0).rejects(someError);
|
|
529
|
+
|
|
530
|
+
await retrieverService.callExternalAPI(
|
|
531
|
+
[],
|
|
532
|
+
anyTimeout,
|
|
533
|
+
null,
|
|
534
|
+
attemptsCount,
|
|
535
|
+
true
|
|
536
|
+
);
|
|
537
|
+
spy.args[0][0].should.be.equal(someError);
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
it("Should pass correct parameters to _performCallAttempt - case default rpsFactor", async function () {
|
|
541
|
+
const retrieverService = new RobustExternalAPICallerService(
|
|
542
|
+
"testService",
|
|
543
|
+
generateProviders(4).providers
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
const attemptsCount = 2;
|
|
547
|
+
const _performCallAttemptStub = sinon.stub(
|
|
548
|
+
retrieverService,
|
|
549
|
+
"_performCallAttempt"
|
|
550
|
+
);
|
|
551
|
+
for (let i = 0; i < attemptsCount; ++i) {
|
|
552
|
+
_performCallAttemptStub.onCall(i).resolves({
|
|
553
|
+
data: null,
|
|
554
|
+
shouldBeForceRetried: false,
|
|
555
|
+
errors: [],
|
|
556
|
+
rpsFactor: RobustExternalAPICallerService.defaultRPSFactor,
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
const someParamsValues = [1, "aaa", { c: "1w2" }];
|
|
561
|
+
const someCancelToken = "some token";
|
|
562
|
+
await retrieverService.callExternalAPI(
|
|
563
|
+
someParamsValues,
|
|
564
|
+
anyTimeout,
|
|
565
|
+
someCancelToken,
|
|
566
|
+
attemptsCount,
|
|
567
|
+
true
|
|
568
|
+
);
|
|
569
|
+
|
|
570
|
+
for (let i = 0; i < attemptsCount; ++i) {
|
|
571
|
+
_performCallAttemptStub.args[i].should.be.deepEqual([
|
|
572
|
+
someParamsValues,
|
|
573
|
+
anyTimeout,
|
|
574
|
+
someCancelToken,
|
|
575
|
+
RobustExternalAPICallerService.defaultRPSFactor,
|
|
576
|
+
true,
|
|
577
|
+
]);
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
it("Should pass correct parameters to _performCallAttempt - case increasing rpsFactor", async function () {
|
|
582
|
+
const retrieverService = new RobustExternalAPICallerService(
|
|
583
|
+
"testService",
|
|
584
|
+
generateProviders(4).providers
|
|
585
|
+
);
|
|
586
|
+
|
|
587
|
+
const attemptsCount = 5;
|
|
588
|
+
const failingAttemptsCount = 3;
|
|
589
|
+
const _performCallAttemptStub = sinon.stub(
|
|
590
|
+
retrieverService,
|
|
591
|
+
"_performCallAttempt"
|
|
592
|
+
);
|
|
593
|
+
const rpsFactors = new Array(failingAttemptsCount + 1)
|
|
594
|
+
.fill(RobustExternalAPICallerService.defaultRPSFactor)
|
|
595
|
+
.map(
|
|
596
|
+
(factor, index) =>
|
|
597
|
+
factor *
|
|
598
|
+
Math.pow(
|
|
599
|
+
RobustExternalAPICallerService.rpsMultiplier,
|
|
600
|
+
index
|
|
601
|
+
)
|
|
602
|
+
);
|
|
603
|
+
|
|
604
|
+
for (let i = 0; i <= failingAttemptsCount; ++i) {
|
|
605
|
+
_performCallAttemptStub.onCall(i).resolves({
|
|
606
|
+
data: i === failingAttemptsCount ? anyData : null,
|
|
607
|
+
shouldBeForceRetried: false,
|
|
608
|
+
errors: [],
|
|
609
|
+
rpsFactor: rpsFactors[i],
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
const someParamsValues = [1, "aaa", { c: "1w2" }];
|
|
613
|
+
const someCancelToken = "some token";
|
|
614
|
+
await retrieverService.callExternalAPI(
|
|
615
|
+
someParamsValues,
|
|
616
|
+
anyTimeout,
|
|
617
|
+
someCancelToken,
|
|
618
|
+
attemptsCount,
|
|
619
|
+
true
|
|
620
|
+
);
|
|
621
|
+
|
|
622
|
+
for (let i = 0; i < failingAttemptsCount + 1; ++i) {
|
|
623
|
+
_performCallAttemptStub.args[i].should.be.deepEqual(
|
|
624
|
+
[
|
|
625
|
+
someParamsValues,
|
|
626
|
+
anyTimeout,
|
|
627
|
+
someCancelToken,
|
|
628
|
+
i === 0
|
|
629
|
+
? RobustExternalAPICallerService.defaultRPSFactor
|
|
630
|
+
: rpsFactors[i - 1],
|
|
631
|
+
true,
|
|
632
|
+
],
|
|
633
|
+
`Attempt ${i} check`
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
it("Should log the 'not enough attempts' error when after all attempts data is null and doNotFailForNowData is true", async function () {
|
|
639
|
+
const retrieverService = new RobustExternalAPICallerService(
|
|
640
|
+
"testService",
|
|
641
|
+
generateProviders(4).providers
|
|
642
|
+
);
|
|
643
|
+
|
|
644
|
+
const spy = sinon.spy(retrieverService, "_logger");
|
|
645
|
+
|
|
646
|
+
const attemptsCount = 3;
|
|
647
|
+
const _performCallAttemptStub = sinon.stub(
|
|
648
|
+
retrieverService,
|
|
649
|
+
"_performCallAttempt"
|
|
650
|
+
);
|
|
651
|
+
for (let i = 0; i < attemptsCount; ++i) {
|
|
652
|
+
_performCallAttemptStub.onCall(i).resolves({
|
|
653
|
+
data: null,
|
|
654
|
+
shouldBeForceRetried: false,
|
|
655
|
+
errors: [],
|
|
656
|
+
rpsFactor: RobustExternalAPICallerService.defaultRPSFactor,
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
await retrieverService.callExternalAPI(
|
|
661
|
+
[],
|
|
662
|
+
anyTimeout,
|
|
663
|
+
null,
|
|
664
|
+
attemptsCount,
|
|
665
|
+
true
|
|
666
|
+
);
|
|
667
|
+
|
|
668
|
+
spy.args[0][0].message.should.be.equal(
|
|
669
|
+
"Failed to retrieve data. It means all attempts have been failed. DEV: add more attempts to this data retrieval"
|
|
670
|
+
);
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
it("Should throw the 'not enough attempts' error when after all attempts data is null and doNotFailForNowData is false", async function () {
|
|
674
|
+
const retrieverService = new RobustExternalAPICallerService(
|
|
675
|
+
"testService",
|
|
676
|
+
generateProviders(4).providers
|
|
677
|
+
);
|
|
678
|
+
|
|
679
|
+
const spy = sinon.spy(retrieverService, "_logger");
|
|
680
|
+
|
|
681
|
+
const attemptsCount = 3;
|
|
682
|
+
const _performCallAttemptStub = sinon.stub(
|
|
683
|
+
retrieverService,
|
|
684
|
+
"_performCallAttempt"
|
|
685
|
+
);
|
|
686
|
+
for (let i = 0; i < attemptsCount; ++i) {
|
|
687
|
+
_performCallAttemptStub.onCall(i).resolves({
|
|
688
|
+
data: null,
|
|
689
|
+
shouldBeForceRetried: false,
|
|
690
|
+
errors: [],
|
|
691
|
+
rpsFactor: RobustExternalAPICallerService.defaultRPSFactor,
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
let error = null;
|
|
696
|
+
try {
|
|
697
|
+
await retrieverService.callExternalAPI(
|
|
698
|
+
[],
|
|
699
|
+
anyTimeout,
|
|
700
|
+
null,
|
|
701
|
+
attemptsCount
|
|
702
|
+
);
|
|
703
|
+
} catch (e) {
|
|
704
|
+
error = e;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
(error == null).should.be.false();
|
|
708
|
+
error.message.should.be.match(
|
|
709
|
+
/.*Failed to retrieve data. It means all attempts have been failed. DEV: add more attempts to this data retrieval/
|
|
710
|
+
);
|
|
711
|
+
});
|
|
712
|
+
|
|
713
|
+
it("Should return the not null data returned by the _performCallAttempt", async function () {
|
|
714
|
+
const retrieverService = new RobustExternalAPICallerService(
|
|
715
|
+
"testService",
|
|
716
|
+
generateProviders(4).providers
|
|
717
|
+
);
|
|
718
|
+
|
|
719
|
+
const attemptsCount = 4;
|
|
720
|
+
const failingAttemptsCount = 2;
|
|
721
|
+
const _performCallAttemptStub = sinon.stub(
|
|
722
|
+
retrieverService,
|
|
723
|
+
"_performCallAttempt"
|
|
724
|
+
);
|
|
725
|
+
for (let i = 0; i <= failingAttemptsCount; ++i) {
|
|
726
|
+
_performCallAttemptStub.onCall(i).resolves({
|
|
727
|
+
data: i === failingAttemptsCount ? anyData : null,
|
|
728
|
+
shouldBeForceRetried: false,
|
|
729
|
+
errors: [],
|
|
730
|
+
rpsFactor: RobustExternalAPICallerService.defaultRPSFactor,
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
const result = await retrieverService.callExternalAPI(
|
|
735
|
+
[],
|
|
736
|
+
anyTimeout,
|
|
737
|
+
null,
|
|
738
|
+
attemptsCount,
|
|
739
|
+
true
|
|
740
|
+
);
|
|
741
|
+
|
|
742
|
+
result.should.be.deepEqual(anyData);
|
|
743
|
+
});
|
|
744
|
+
});
|
|
745
|
+
});
|