@chainlink/external-adapter-framework 0.0.15 → 0.0.17

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.
Files changed (186) hide show
  1. package/adapter.js +128 -0
  2. package/background-executor.js +45 -0
  3. package/cache/factory.js +58 -0
  4. package/cache/index.js +173 -0
  5. package/cache/local.js +83 -0
  6. package/cache/metrics.js +120 -0
  7. package/cache/redis.js +100 -0
  8. package/chainlink-external-adapter-framework-v0.0.6.tgz +0 -0
  9. package/config/index.js +366 -0
  10. package/config/provider-limits.js +74 -0
  11. package/examples/bank-frick/accounts.js +192 -0
  12. package/examples/bank-frick/config/index.js +54 -0
  13. package/examples/bank-frick/index.js +15 -0
  14. package/examples/bank-frick/util.js +39 -0
  15. package/examples/coingecko/batch-warming.js +53 -0
  16. package/examples/coingecko/index.js +11 -0
  17. package/examples/coingecko/rest.js +51 -0
  18. package/examples/coingecko/src/config/index.js +13 -0
  19. package/examples/coingecko/src/config/overrides.json +10826 -0
  20. package/examples/coingecko/src/cryptoUtils.js +41 -0
  21. package/examples/coingecko/src/endpoint/coins.js +33 -0
  22. package/examples/coingecko/src/endpoint/crypto-marketcap.js +46 -0
  23. package/examples/coingecko/src/endpoint/crypto-volume.js +46 -0
  24. package/examples/coingecko/src/endpoint/crypto.js +47 -0
  25. package/examples/coingecko/src/endpoint/dominance.js +26 -0
  26. package/examples/coingecko/src/endpoint/global-marketcap.js +26 -0
  27. package/examples/coingecko/src/endpoint/index.js +15 -0
  28. package/examples/coingecko/src/globalUtils.js +48 -0
  29. package/examples/coingecko/src/index.js +14 -0
  30. package/examples/coingecko/test/e2e/adapter.test.js +262 -0
  31. package/examples/coingecko/test/integration/adapter.test.js +264 -0
  32. package/examples/coingecko/test/integration/capturedRequests.json +1 -0
  33. package/examples/coingecko/test/integration/fixtures.js +41 -0
  34. package/examples/coingecko-old/batch-warming.js +53 -0
  35. package/examples/coingecko-old/index.js +11 -0
  36. package/examples/coingecko-old/rest.js +51 -0
  37. package/examples/ncfx/config/index.js +15 -0
  38. package/examples/ncfx/index.js +11 -0
  39. package/examples/ncfx/websocket.js +73 -0
  40. package/index.js +127 -0
  41. package/metrics/constants.js +25 -0
  42. package/metrics/index.js +122 -0
  43. package/metrics/util.js +9 -0
  44. package/package.json +5 -15
  45. package/rate-limiting/background/fixed-frequency.js +35 -0
  46. package/rate-limiting/index.js +84 -0
  47. package/rate-limiting/metrics.js +44 -0
  48. package/rate-limiting/request/simple-counting.js +62 -0
  49. package/test.js +6 -0
  50. package/transports/batch-warming.js +101 -0
  51. package/transports/index.js +87 -0
  52. package/transports/metrics.js +105 -0
  53. package/transports/rest.js +138 -0
  54. package/transports/util.js +86 -0
  55. package/transports/websocket.js +166 -0
  56. package/util/index.js +35 -0
  57. package/util/logger.js +62 -0
  58. package/util/recordRequests.js +45 -0
  59. package/util/request.js +2 -0
  60. package/util/subscription-set/expiring-sorted-set.js +47 -0
  61. package/util/subscription-set/subscription-set.js +19 -0
  62. package/util/test-payload-loader.js +83 -0
  63. package/validation/error.js +79 -0
  64. package/validation/index.js +91 -0
  65. package/validation/input-params.js +30 -0
  66. package/validation/override-functions.js +40 -0
  67. package/validation/overrideFunctions.js +40 -0
  68. package/validation/preset-tokens.json +23 -0
  69. package/validation/validator.js +303 -0
  70. package/.c8rc.json +0 -3
  71. package/.eslintignore +0 -10
  72. package/.eslintrc.js +0 -96
  73. package/.github/README.MD +0 -42
  74. package/.github/actions/setup/action.yaml +0 -13
  75. package/.github/workflows/label.yaml +0 -39
  76. package/.github/workflows/main.yaml +0 -39
  77. package/.github/workflows/publish.yaml +0 -17
  78. package/.prettierignore +0 -13
  79. package/.yarnrc +0 -0
  80. package/README.md +0 -103
  81. package/dist/examples/coingecko/test/e2e/adapter.test.ts.js +0 -82953
  82. package/dist/examples/coingecko/test/integration/adapter.test.ts.js +0 -91672
  83. package/dist/main.js +0 -72703
  84. package/docker-compose.yaml +0 -35
  85. package/env.sh +0 -54
  86. package/env2.sh +0 -55
  87. package/jest.config.js +0 -5
  88. package/publish.sh +0 -0
  89. package/src/adapter.ts +0 -263
  90. package/src/background-executor.ts +0 -52
  91. package/src/cache/factory.ts +0 -26
  92. package/src/cache/index.ts +0 -258
  93. package/src/cache/local.ts +0 -73
  94. package/src/cache/metrics.ts +0 -112
  95. package/src/cache/redis.ts +0 -93
  96. package/src/config/index.ts +0 -517
  97. package/src/config/provider-limits.ts +0 -127
  98. package/src/examples/bank-frick/README.MD +0 -10
  99. package/src/examples/bank-frick/accounts.ts +0 -246
  100. package/src/examples/bank-frick/config/index.ts +0 -53
  101. package/src/examples/bank-frick/index.ts +0 -13
  102. package/src/examples/bank-frick/types.d.ts +0 -38
  103. package/src/examples/bank-frick/util.ts +0 -55
  104. package/src/examples/coingecko/src/config/index.ts +0 -12
  105. package/src/examples/coingecko/src/config/overrides.json +0 -10826
  106. package/src/examples/coingecko/src/cryptoUtils.ts +0 -88
  107. package/src/examples/coingecko/src/endpoint/coins.ts +0 -54
  108. package/src/examples/coingecko/src/endpoint/crypto-marketcap.ts +0 -66
  109. package/src/examples/coingecko/src/endpoint/crypto-volume.ts +0 -66
  110. package/src/examples/coingecko/src/endpoint/crypto.ts +0 -63
  111. package/src/examples/coingecko/src/endpoint/dominance.ts +0 -40
  112. package/src/examples/coingecko/src/endpoint/global-marketcap.ts +0 -40
  113. package/src/examples/coingecko/src/endpoint/index.ts +0 -6
  114. package/src/examples/coingecko/src/globalUtils.ts +0 -78
  115. package/src/examples/coingecko/src/index.ts +0 -17
  116. package/src/examples/coingecko/test/e2e/adapter.test.ts +0 -278
  117. package/src/examples/coingecko/test/integration/__snapshots__/adapter.test.ts.snap +0 -15
  118. package/src/examples/coingecko/test/integration/adapter.test.ts +0 -281
  119. package/src/examples/coingecko/test/integration/capturedRequests.json +0 -1
  120. package/src/examples/coingecko/test/integration/fixtures.ts +0 -42
  121. package/src/examples/coingecko-old/batch-warming.ts +0 -79
  122. package/src/examples/coingecko-old/index.ts +0 -9
  123. package/src/examples/coingecko-old/rest.ts +0 -77
  124. package/src/examples/ncfx/config/index.ts +0 -12
  125. package/src/examples/ncfx/index.ts +0 -9
  126. package/src/examples/ncfx/websocket.ts +0 -99
  127. package/src/index.ts +0 -149
  128. package/src/metrics/constants.ts +0 -23
  129. package/src/metrics/index.ts +0 -115
  130. package/src/metrics/util.ts +0 -18
  131. package/src/rate-limiting/background/fixed-frequency.ts +0 -45
  132. package/src/rate-limiting/index.ts +0 -100
  133. package/src/rate-limiting/metrics.ts +0 -18
  134. package/src/rate-limiting/request/simple-counting.ts +0 -76
  135. package/src/transports/batch-warming.ts +0 -127
  136. package/src/transports/index.ts +0 -152
  137. package/src/transports/metrics.ts +0 -95
  138. package/src/transports/rest.ts +0 -168
  139. package/src/transports/util.ts +0 -63
  140. package/src/transports/websocket.ts +0 -245
  141. package/src/util/index.ts +0 -23
  142. package/src/util/logger.ts +0 -69
  143. package/src/util/recordRequests.ts +0 -47
  144. package/src/util/request.ts +0 -117
  145. package/src/util/subscription-set/expiring-sorted-set.ts +0 -54
  146. package/src/util/subscription-set/subscription-set.ts +0 -35
  147. package/src/util/test-payload-loader.ts +0 -87
  148. package/src/validation/error.ts +0 -116
  149. package/src/validation/index.ts +0 -110
  150. package/src/validation/input-params.ts +0 -45
  151. package/src/validation/override-functions.ts +0 -44
  152. package/src/validation/overrideFunctions.ts +0 -44
  153. package/src/validation/preset-tokens.json +0 -23
  154. package/src/validation/validator.ts +0 -384
  155. package/test/adapter.test.ts +0 -27
  156. package/test/background-executor.test.ts +0 -108
  157. package/test/cache/cache-key.test.ts +0 -114
  158. package/test/cache/helper.ts +0 -100
  159. package/test/cache/local.test.ts +0 -54
  160. package/test/cache/redis.test.ts +0 -89
  161. package/test/correlation.test.ts +0 -114
  162. package/test/index.test.ts +0 -37
  163. package/test/metrics/feed-id.test.ts +0 -38
  164. package/test/metrics/helper.ts +0 -14
  165. package/test/metrics/labels.test.ts +0 -36
  166. package/test/metrics/metrics.test.ts +0 -267
  167. package/test/metrics/redis-metrics.test.ts +0 -113
  168. package/test/metrics/warmer-metrics.test.ts +0 -193
  169. package/test/metrics/ws-metrics.test.ts +0 -225
  170. package/test/rate-limit-config.test.ts +0 -242
  171. package/test/smoke/smoke.test.ts +0 -166
  172. package/test/smoke/test-payload-fail.json +0 -3
  173. package/test/smoke/test-payload.js +0 -22
  174. package/test/smoke/test-payload.json +0 -7
  175. package/test/transports/batch.test.ts +0 -466
  176. package/test/transports/rest.test.ts +0 -242
  177. package/test/transports/websocket.test.ts +0 -183
  178. package/test/tsconfig.json +0 -5
  179. package/test/util.ts +0 -77
  180. package/test/validation.test.ts +0 -178
  181. package/test.sh +0 -20
  182. package/test2.sh +0 -2
  183. package/tsconfig.json +0 -28
  184. package/typedoc.json +0 -6
  185. package/webpack.config.js +0 -57
  186. package/yarn-error.log +0 -3778
@@ -1,267 +0,0 @@
1
- import untypedTest, { TestFn } from 'ava'
2
- import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'
3
- import { AddressInfo } from 'net'
4
- import nock from 'nock'
5
- import { expose } from '../../src'
6
- import { Adapter, AdapterEndpoint } from '../../src/adapter'
7
- import { EmptySettings } from '../../src/config'
8
- import { RestTransport } from '../../src/transports'
9
- import { AdapterRequest, AdapterResponse } from '../../src/util'
10
- import { parsePromMetrics } from './helper'
11
-
12
- const test = untypedTest as TestFn<{
13
- serverAddress: string
14
- }>
15
-
16
- const URL = 'http://test-url.com'
17
-
18
- interface AdapterRequestParams {
19
- from: string
20
- to: string
21
- }
22
-
23
- interface ProviderRequestBody {
24
- base: string
25
- quote: string
26
- }
27
-
28
- interface ProviderResponseBody {
29
- price: number
30
- }
31
-
32
- const endpoint = '/price'
33
-
34
- const createAdapterEndpoint = (): AdapterEndpoint => {
35
- const restEndpointTransport = new RestTransport<
36
- AdapterRequestParams,
37
- ProviderRequestBody,
38
- ProviderResponseBody,
39
- EmptySettings
40
- >({
41
- prepareRequest: (
42
- req: AdapterRequest<AdapterRequestParams>,
43
- ): AxiosRequestConfig<ProviderRequestBody> => {
44
- return {
45
- baseURL: URL,
46
- url: endpoint,
47
- method: 'GET',
48
- params: {
49
- base: req.requestContext.data.from,
50
- quote: req.requestContext.data.to,
51
- },
52
- }
53
- },
54
- parseResponse: (
55
- req: AdapterRequest<AdapterRequestParams>,
56
- res: AxiosResponse<ProviderResponseBody>,
57
- ): AdapterResponse<ProviderResponseBody> => {
58
- return {
59
- data: res.data,
60
- statusCode: 200,
61
- result: res.data.price,
62
- }
63
- },
64
- options: {
65
- coalescing: true,
66
- },
67
- })
68
-
69
- return {
70
- name: 'test',
71
- inputParameters: {
72
- from: {
73
- type: 'string',
74
- required: true,
75
- },
76
- to: {
77
- type: 'string',
78
- required: true,
79
- },
80
- },
81
- transport: restEndpointTransport,
82
- }
83
- }
84
-
85
- const from = 'ETH'
86
- const to = 'USD'
87
- const price = 1234
88
-
89
- test.before(async (t) => {
90
- process.env['METRICS_ENABLED'] = 'true'
91
- process.env['METRICS_PORT'] = '9090'
92
- process.env['npm_package_version'] = '1'
93
- const adapter: Adapter = {
94
- name: 'test',
95
- defaultEndpoint: 'test',
96
- endpoints: [createAdapterEndpoint()],
97
- }
98
- const server = await expose(adapter)
99
- if (!server) {
100
- throw 'Server did not start'
101
- }
102
- t.context.serverAddress = `http://localhost:${(server.address() as AddressInfo).port}`
103
- })
104
-
105
- test.serial('Test http requests total metrics (data provider hit)', async (t) => {
106
- const metricsAddress = `http://localhost:${process.env['METRICS_PORT']}/metrics`
107
- nock(URL)
108
- .get(endpoint)
109
- .query({
110
- base: from,
111
- quote: to,
112
- })
113
- .reply(200, {
114
- price,
115
- })
116
-
117
- await axios.post(t.context.serverAddress, {
118
- data: {
119
- from,
120
- to,
121
- },
122
- })
123
-
124
- const response = await axios.get(metricsAddress)
125
- const metricsMap = parsePromMetrics(response.data)
126
- const expectedLabel =
127
- '{method="POST",feed_id="|from:eth|to:usd",status_code="200",type="dataProviderHit",provider_status_code="200",app_name="test",app_version="undefined"}'
128
- t.is(metricsMap.get(`http_requests_total${expectedLabel}`), 1)
129
- })
130
-
131
- test.serial('Test http request duration metrics', async (t) => {
132
- const metricsAddress = `http://localhost:${process.env['METRICS_PORT']}/metrics`
133
- const response = await axios.get(metricsAddress)
134
- const metricsMap = parsePromMetrics(response.data)
135
- const expectedLabel = '{app_name="test",app_version="undefined"}'
136
- const responseTime = metricsMap.get(`http_request_duration_seconds_sum${expectedLabel}`)
137
- if (responseTime !== undefined) {
138
- t.is(typeof responseTime === 'number', true)
139
- t.is(responseTime > 0, true)
140
- } else {
141
- t.fail('Response time did not record')
142
- }
143
- })
144
-
145
- test.serial('Test data provider requests metrics', async (t) => {
146
- const metricsAddress = `http://localhost:${process.env['METRICS_PORT']}/metrics`
147
- const response = await axios.get(metricsAddress)
148
- const metricsMap = parsePromMetrics(response.data)
149
- const expectedLabel =
150
- '{provider_status_code="200",method="GET",app_name="test",app_version="undefined"}'
151
- t.is(metricsMap.get(`data_provider_requests${expectedLabel}`), 1)
152
- })
153
-
154
- test.serial('Test data provider request duration metrics', async (t) => {
155
- const metricsAddress = `http://localhost:${process.env['METRICS_PORT']}/metrics`
156
- const response = await axios.get(metricsAddress)
157
- const metricsMap = parsePromMetrics(response.data)
158
- const expectedLabel = '{app_name="test",app_version="undefined"}'
159
- const responseTime = metricsMap.get(`data_provider_request_duration_seconds_sum${expectedLabel}`)
160
- if (responseTime !== undefined) {
161
- t.is(typeof responseTime === 'number', true)
162
- t.is(responseTime > 0, true)
163
- } else {
164
- t.fail('Response time did not record')
165
- }
166
- })
167
-
168
- test.serial('Test cache set count metrics', async (t) => {
169
- const metricsAddress = `http://localhost:${process.env['METRICS_PORT']}/metrics`
170
- const response = await axios.get(metricsAddress)
171
- const metricsMap = parsePromMetrics(response.data)
172
- const expectedLabel =
173
- '{participant_id="test-|from:eth|to:usd",feed_id="|from:eth|to:usd",cache_type="local",app_name="test",app_version="undefined"}'
174
- t.is(metricsMap.get(`cache_data_set_count${expectedLabel}`), 1)
175
- })
176
-
177
- test.serial('Test cache max age metrics', async (t) => {
178
- const metricsAddress = `http://localhost:${process.env['METRICS_PORT']}/metrics`
179
- const response = await axios.get(metricsAddress)
180
- const metricsMap = parsePromMetrics(response.data)
181
- const expectedLabel =
182
- '{participant_id="test-|from:eth|to:usd",feed_id="|from:eth|to:usd",cache_type="local",app_name="test",app_version="undefined"}'
183
- t.is(metricsMap.get(`cache_data_max_age${expectedLabel}`), 90000)
184
- })
185
-
186
- test.serial('Test cache set staleness metrics', async (t) => {
187
- const metricsAddress = `http://localhost:${process.env['METRICS_PORT']}/metrics`
188
- const response = await axios.get(metricsAddress)
189
- const metricsMap = parsePromMetrics(response.data)
190
- const expectedLabel =
191
- '{participant_id="test-|from:eth|to:usd",feed_id="|from:eth|to:usd",cache_type="local",app_name="test",app_version="undefined"}'
192
- const staleness = metricsMap.get(`cache_data_staleness_seconds${expectedLabel}`)
193
- if (staleness !== undefined) {
194
- t.is(typeof staleness === 'number', true)
195
- t.is(staleness === 0, true)
196
- } else {
197
- t.fail('Staleness was not retrieved')
198
- }
199
- })
200
-
201
- test.serial('Test credit spent metrics', async (t) => {
202
- const metricsAddress = `http://localhost:${process.env['METRICS_PORT']}/metrics`
203
- const response = await axios.get(metricsAddress)
204
- const metricsMap = parsePromMetrics(response.data)
205
- const expectedLabel =
206
- '{feed_id="|from:eth|to:usd",participant_id="test-|from:eth|to:usd",app_name="test",app_version="undefined"}'
207
- t.is(metricsMap.get(`rate_limit_credits_spent_total${expectedLabel}`), 1)
208
- })
209
-
210
- test.serial('Test http requests total metrics (cache hit)', async (t) => {
211
- const metricsAddress = `http://localhost:${process.env['METRICS_PORT']}/metrics`
212
- nock(URL)
213
- .get(endpoint)
214
- .query({
215
- base: from,
216
- quote: to,
217
- })
218
- .reply(200, {
219
- price,
220
- })
221
-
222
- await axios.post(t.context.serverAddress, {
223
- data: {
224
- from,
225
- to,
226
- },
227
- })
228
-
229
- const response = await axios.get(metricsAddress)
230
- const metricsMap = parsePromMetrics(response.data)
231
- const expectedLabel =
232
- '{method="POST",feed_id="|from:eth|to:usd",status_code="200",type="cacheHit",app_name="test",app_version="undefined"}'
233
- t.is(metricsMap.get(`http_requests_total${expectedLabel}`), 1)
234
- })
235
-
236
- test.serial('Test cache get count metrics', async (t) => {
237
- const metricsAddress = `http://localhost:${process.env['METRICS_PORT']}/metrics`
238
- const response = await axios.get(metricsAddress)
239
- const metricsMap = parsePromMetrics(response.data)
240
- const expectedLabel =
241
- '{participant_id="test-|from:eth|to:usd",feed_id="|from:eth|to:usd",cache_type="local",app_name="test",app_version="undefined"}'
242
- t.is(metricsMap.get(`cache_data_get_count${expectedLabel}`), 1)
243
- })
244
-
245
- test.serial('Test cache get value metrics', async (t) => {
246
- const metricsAddress = `http://localhost:${process.env['METRICS_PORT']}/metrics`
247
- const response = await axios.get(metricsAddress)
248
- const metricsMap = parsePromMetrics(response.data)
249
- const expectedLabel =
250
- '{participant_id="test-|from:eth|to:usd",feed_id="|from:eth|to:usd",cache_type="local",app_name="test",app_version="undefined"}'
251
- t.is(metricsMap.get(`cache_data_get_values${expectedLabel}`), 1234)
252
- })
253
-
254
- test.serial('Test cache get staleness metrics', async (t) => {
255
- const metricsAddress = `http://localhost:${process.env['METRICS_PORT']}/metrics`
256
- const response = await axios.get(metricsAddress)
257
- const metricsMap = parsePromMetrics(response.data)
258
- const expectedLabel =
259
- '{participant_id="test-|from:eth|to:usd",feed_id="|from:eth|to:usd",cache_type="local",app_name="test",app_version="undefined"}'
260
- const staleness = metricsMap.get(`cache_data_staleness_seconds${expectedLabel}`)
261
- if (staleness !== undefined) {
262
- t.is(typeof staleness === 'number', true)
263
- t.is(staleness > 0, true)
264
- } else {
265
- t.fail('Staleness was not retrieved')
266
- }
267
- })
@@ -1,113 +0,0 @@
1
- import untypedTest, { TestFn } from 'ava'
2
- import axios from 'axios'
3
- import Redis from 'ioredis'
4
- import { AddressInfo } from 'ws'
5
- import { expose } from '../../src'
6
- import { Adapter, AdapterDependencies, AdapterEndpoint } from '../../src/adapter'
7
- import { Cache, LocalCache, RedisCache } from '../../src/cache'
8
- import { SettingsMap } from '../../src/config'
9
- import { Transport } from '../../src/transports'
10
- import { BasicCacheSetterTransport } from '../cache/helper'
11
- import { NopTransport } from '../util'
12
- import { parsePromMetrics } from './helper'
13
-
14
- export const test = untypedTest as TestFn<{
15
- serverAddress: string
16
- cache: Cache
17
- adapterEndpoint: AdapterEndpoint
18
- }>
19
-
20
- class RedisMock {
21
- store = new LocalCache<string>()
22
-
23
- get(key: string) {
24
- return this.store.get(key)
25
- }
26
-
27
- del(key: string) {
28
- return this.store.delete(key)
29
- }
30
-
31
- set(key: string, value: string, px: 'PX', ttl: number) {
32
- return this.store.set(key, value, ttl)
33
- }
34
-
35
- multi() {
36
- return new CommandChainMock(this)
37
- }
38
- }
39
-
40
- class CommandChainMock {
41
- promises: Promise<unknown>[] = []
42
- constructor(private redisMock: RedisMock) {}
43
-
44
- set(key: string, value: string, px: 'PX', ttl: number) {
45
- this.promises.push(this.redisMock.set(key, value, px, ttl))
46
- return this
47
- }
48
-
49
- exec() {
50
- return Promise.all(this.promises)
51
- }
52
- }
53
-
54
- test.before(async (t) => {
55
- process.env['METRICS_ENABLED'] = 'true'
56
- process.env['METRICS_PORT'] = '9091'
57
- const adapter: Adapter = {
58
- name: 'test',
59
- defaultEndpoint: 'test',
60
- endpoints: [
61
- {
62
- name: 'test',
63
- inputParameters: {
64
- base: {
65
- type: 'string',
66
- required: true,
67
- },
68
- factor: {
69
- type: 'number',
70
- required: true,
71
- },
72
- },
73
- transport: new BasicCacheSetterTransport() as Transport<unknown, unknown, SettingsMap>,
74
- },
75
- {
76
- name: 'nowork',
77
- inputParameters: {},
78
- transport: new NopTransport(),
79
- },
80
- ],
81
- envDefaultOverrides: {
82
- CACHE_POLLING_SLEEP_MS: 10,
83
- CACHE_POLLING_MAX_RETRIES: 3,
84
- },
85
- }
86
-
87
- const cache = new RedisCache(new RedisMock() as unknown as Redis) // Fake redis
88
- const dependencies: Partial<AdapterDependencies> = {
89
- cache,
90
- }
91
-
92
- t.context.cache = cache
93
- const server = await expose(adapter, dependencies)
94
- if (!server) {
95
- throw 'Server did not start'
96
- }
97
- t.context.serverAddress = `http://localhost:${(server.address() as AddressInfo).port}`
98
- })
99
-
100
- test.serial('Test redis sent command metric', async (t) => {
101
- const data = {
102
- base: 'eth',
103
- factor: 123,
104
- }
105
-
106
- await axios.post(t.context.serverAddress, { data })
107
- const metricsAddress = `http://localhost:${process.env['METRICS_PORT']}/metrics`
108
- const response = await axios.get(metricsAddress)
109
- const metricsMap = parsePromMetrics(response.data)
110
- const expectedLabel =
111
- '{status="SUCCESS",function_name="exec",app_name="test",app_version="undefined"}'
112
- t.is(metricsMap.get(`redis_commands_sent_count${expectedLabel}`), 1)
113
- })
@@ -1,193 +0,0 @@
1
- import FakeTimers from '@sinonjs/fake-timers'
2
- import untypedTest, { TestFn } from 'ava'
3
- import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'
4
- import { AddressInfo } from 'net'
5
- import nock from 'nock'
6
- import { expose } from '../../src'
7
- import { Adapter } from '../../src/adapter'
8
- import { SettingsMap } from '../../src/config'
9
- import { DEFAULT_SHARED_MS_BETWEEN_REQUESTS } from '../../src/rate-limiting'
10
- import { BatchWarmingTransport } from '../../src/transports'
11
- import { ProviderResult } from '../../src/util'
12
- import { MockCache } from '../util'
13
- import { parsePromMetrics } from './helper'
14
-
15
- const test = untypedTest as TestFn<{
16
- serverAddress: string
17
- cache: MockCache
18
- }>
19
-
20
- const URL = 'http://test-url.com'
21
- const endpoint = '/price'
22
-
23
- interface AdapterRequestParams {
24
- from: string
25
- to: string
26
- }
27
-
28
- interface ProviderRequestBody {
29
- pairs: Array<{
30
- base: string
31
- quote: string
32
- }>
33
- }
34
-
35
- interface ProviderResponseBody {
36
- prices: Array<{
37
- pair: string
38
- price: number
39
- }>
40
- }
41
- const clock = FakeTimers.install({ shouldAdvanceTime: true, advanceTimeDelta: 100 })
42
-
43
- test.before(async (t) => {
44
- nock.disableNetConnect()
45
- nock.enableNetConnect('localhost')
46
- process.env['METRICS_ENABLED'] = 'true'
47
- process.env['METRICS_PORT'] = '9092'
48
- // Disable retries to make the testing flow easier
49
- process.env['CACHE_POLLING_MAX_RETRIES'] = '0'
50
-
51
- const adapter: Adapter = {
52
- name: 'test',
53
- defaultEndpoint: 'test',
54
- endpoints: [
55
- {
56
- name: 'test',
57
- inputParameters,
58
- transport: new MockBatchWarmingTransport(),
59
- },
60
- ],
61
- }
62
-
63
- // Create mocked cache so we can listen when values are set
64
- // This is a more reliable method than expecting precise clock timings
65
- const mockCache = new MockCache()
66
-
67
- // Start the adapter
68
- const server = await expose(adapter, {
69
- cache: mockCache,
70
- })
71
- t.context.serverAddress = `http://localhost:${(server?.address() as AddressInfo)?.port}`
72
- t.context.cache = mockCache
73
- })
74
-
75
- test.after(() => {
76
- nock.restore()
77
- clock.uninstall()
78
- })
79
-
80
- class MockBatchWarmingTransport extends BatchWarmingTransport<
81
- AdapterRequestParams,
82
- ProviderRequestBody,
83
- ProviderResponseBody,
84
- SettingsMap
85
- > {
86
- constructor() {
87
- super({
88
- prepareRequest: (params: AdapterRequestParams[]): AxiosRequestConfig<ProviderRequestBody> => {
89
- return {
90
- baseURL: URL,
91
- url: '/price',
92
- method: 'POST',
93
- data: {
94
- pairs: params.map((p) => ({ base: p.from, quote: p.to })),
95
- },
96
- }
97
- },
98
- parseResponse: (
99
- params: AdapterRequestParams[],
100
- res: AxiosResponse<ProviderResponseBody>,
101
- ): ProviderResult<AdapterRequestParams>[] => {
102
- return res.data.prices.map((p) => {
103
- const [from, to] = p.pair.split('/')
104
- return {
105
- params: { from, to },
106
- value: p.price,
107
- }
108
- })
109
- },
110
- })
111
- }
112
- }
113
-
114
- const from = 'ETH'
115
- const to = 'USD'
116
- const price = 1234
117
-
118
- nock(URL)
119
- .post(endpoint, {
120
- pairs: [
121
- {
122
- base: from,
123
- quote: to,
124
- },
125
- ],
126
- })
127
- .reply(200, {
128
- prices: [
129
- {
130
- pair: `${from}/${to}`,
131
- price,
132
- },
133
- ],
134
- })
135
- .persist()
136
-
137
- const inputParameters = {
138
- from: {
139
- type: 'string',
140
- required: true,
141
- },
142
- to: {
143
- type: 'string',
144
- required: true,
145
- },
146
- } as const
147
-
148
- test.serial('Test cache warmer active metric', async (t) => {
149
- const makeRequest = () =>
150
- axios.post(t.context.serverAddress, {
151
- data: {
152
- from,
153
- to,
154
- },
155
- })
156
-
157
- // Expect the first response to time out
158
- // The polling behavior is tested in the cache tests, so this is easier here.
159
- // Start the request:
160
- const errorPromise: Promise<AxiosError | undefined> = t.throwsAsync(makeRequest)
161
- // Advance enough time for the initial request async flow
162
- clock.tickAsync(10)
163
- // Wait for the failed cache get -> instant 504
164
- const error = await errorPromise
165
- t.is(error?.response?.status, 504)
166
-
167
- // Advance clock so that the batch warmer executes once again and wait for the cache to be set
168
- const cacheValueSetPromise = t.context.cache.waitForNextSet()
169
- await clock.tickAsync(DEFAULT_SHARED_MS_BETWEEN_REQUESTS + 10)
170
- await cacheValueSetPromise
171
-
172
- // Second request should find the response in the cache
173
- let response = await makeRequest()
174
-
175
- t.is(response.status, 200)
176
- const metricsAddress = `http://localhost:${process.env['METRICS_PORT']}/metrics`
177
- response = await axios.get(metricsAddress)
178
- let metricsMap = parsePromMetrics(response.data)
179
- let expectedLabel = '{isBatched="true",app_name="test",app_version="undefined"}'
180
- t.is(metricsMap.get(`cache_warmer_get_count${expectedLabel}`), 1)
181
-
182
- // Wait until the cache expires, and the subscription is out
183
- await clock.tickAsync(90001)
184
-
185
- // Now that the cache is out and the subscription no longer there, this should time out
186
- const error2: AxiosError | undefined = await t.throwsAsync(makeRequest)
187
- t.is(error2?.response?.status, 504)
188
-
189
- response = await axios.get(metricsAddress)
190
- metricsMap = parsePromMetrics(response.data)
191
- expectedLabel = '{isBatched="true",app_name="test",app_version="undefined"}'
192
- t.is(metricsMap.get(`cache_warmer_get_count${expectedLabel}`), 0)
193
- })