@chainlink/external-adapter-framework 0.0.15 → 0.0.16

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 (183) 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/src/config/index.js +13 -0
  16. package/examples/coingecko/src/config/overrides.json +10826 -0
  17. package/examples/coingecko/src/cryptoUtils.js +41 -0
  18. package/examples/coingecko/src/endpoint/coins.js +33 -0
  19. package/examples/coingecko/src/endpoint/crypto-marketcap.js +46 -0
  20. package/examples/coingecko/src/endpoint/crypto-volume.js +46 -0
  21. package/examples/coingecko/src/endpoint/crypto.js +47 -0
  22. package/examples/coingecko/src/endpoint/dominance.js +26 -0
  23. package/examples/coingecko/src/endpoint/global-marketcap.js +26 -0
  24. package/examples/coingecko/src/endpoint/index.js +15 -0
  25. package/examples/coingecko/src/globalUtils.js +48 -0
  26. package/examples/coingecko/src/index.js +14 -0
  27. package/examples/coingecko/test/e2e/adapter.test.js +262 -0
  28. package/examples/coingecko/test/integration/adapter.test.js +264 -0
  29. package/examples/coingecko/test/integration/capturedRequests.json +1 -0
  30. package/examples/coingecko/test/integration/fixtures.js +41 -0
  31. package/examples/coingecko-old/batch-warming.js +53 -0
  32. package/examples/coingecko-old/index.js +11 -0
  33. package/examples/coingecko-old/rest.js +51 -0
  34. package/examples/ncfx/config/index.js +15 -0
  35. package/examples/ncfx/index.js +11 -0
  36. package/examples/ncfx/websocket.js +73 -0
  37. package/index.js +127 -0
  38. package/metrics/constants.js +25 -0
  39. package/metrics/index.js +122 -0
  40. package/metrics/util.js +9 -0
  41. package/package.json +5 -15
  42. package/rate-limiting/background/fixed-frequency.js +35 -0
  43. package/rate-limiting/index.js +84 -0
  44. package/rate-limiting/metrics.js +44 -0
  45. package/rate-limiting/request/simple-counting.js +62 -0
  46. package/test.js +6 -0
  47. package/transports/batch-warming.js +101 -0
  48. package/transports/index.js +87 -0
  49. package/transports/metrics.js +105 -0
  50. package/transports/rest.js +138 -0
  51. package/transports/util.js +86 -0
  52. package/transports/websocket.js +166 -0
  53. package/util/index.js +35 -0
  54. package/util/logger.js +62 -0
  55. package/util/recordRequests.js +45 -0
  56. package/util/request.js +2 -0
  57. package/util/subscription-set/expiring-sorted-set.js +47 -0
  58. package/util/subscription-set/subscription-set.js +19 -0
  59. package/util/test-payload-loader.js +83 -0
  60. package/validation/error.js +79 -0
  61. package/validation/index.js +91 -0
  62. package/validation/input-params.js +30 -0
  63. package/validation/override-functions.js +40 -0
  64. package/validation/overrideFunctions.js +40 -0
  65. package/validation/preset-tokens.json +23 -0
  66. package/validation/validator.js +303 -0
  67. package/.c8rc.json +0 -3
  68. package/.eslintignore +0 -10
  69. package/.eslintrc.js +0 -96
  70. package/.github/README.MD +0 -42
  71. package/.github/actions/setup/action.yaml +0 -13
  72. package/.github/workflows/label.yaml +0 -39
  73. package/.github/workflows/main.yaml +0 -39
  74. package/.github/workflows/publish.yaml +0 -17
  75. package/.prettierignore +0 -13
  76. package/.yarnrc +0 -0
  77. package/README.md +0 -103
  78. package/dist/examples/coingecko/test/e2e/adapter.test.ts.js +0 -82953
  79. package/dist/examples/coingecko/test/integration/adapter.test.ts.js +0 -91672
  80. package/dist/main.js +0 -72703
  81. package/docker-compose.yaml +0 -35
  82. package/env.sh +0 -54
  83. package/env2.sh +0 -55
  84. package/jest.config.js +0 -5
  85. package/publish.sh +0 -0
  86. package/src/adapter.ts +0 -263
  87. package/src/background-executor.ts +0 -52
  88. package/src/cache/factory.ts +0 -26
  89. package/src/cache/index.ts +0 -258
  90. package/src/cache/local.ts +0 -73
  91. package/src/cache/metrics.ts +0 -112
  92. package/src/cache/redis.ts +0 -93
  93. package/src/config/index.ts +0 -517
  94. package/src/config/provider-limits.ts +0 -127
  95. package/src/examples/bank-frick/README.MD +0 -10
  96. package/src/examples/bank-frick/accounts.ts +0 -246
  97. package/src/examples/bank-frick/config/index.ts +0 -53
  98. package/src/examples/bank-frick/index.ts +0 -13
  99. package/src/examples/bank-frick/types.d.ts +0 -38
  100. package/src/examples/bank-frick/util.ts +0 -55
  101. package/src/examples/coingecko/src/config/index.ts +0 -12
  102. package/src/examples/coingecko/src/config/overrides.json +0 -10826
  103. package/src/examples/coingecko/src/cryptoUtils.ts +0 -88
  104. package/src/examples/coingecko/src/endpoint/coins.ts +0 -54
  105. package/src/examples/coingecko/src/endpoint/crypto-marketcap.ts +0 -66
  106. package/src/examples/coingecko/src/endpoint/crypto-volume.ts +0 -66
  107. package/src/examples/coingecko/src/endpoint/crypto.ts +0 -63
  108. package/src/examples/coingecko/src/endpoint/dominance.ts +0 -40
  109. package/src/examples/coingecko/src/endpoint/global-marketcap.ts +0 -40
  110. package/src/examples/coingecko/src/endpoint/index.ts +0 -6
  111. package/src/examples/coingecko/src/globalUtils.ts +0 -78
  112. package/src/examples/coingecko/src/index.ts +0 -17
  113. package/src/examples/coingecko/test/e2e/adapter.test.ts +0 -278
  114. package/src/examples/coingecko/test/integration/__snapshots__/adapter.test.ts.snap +0 -15
  115. package/src/examples/coingecko/test/integration/adapter.test.ts +0 -281
  116. package/src/examples/coingecko/test/integration/capturedRequests.json +0 -1
  117. package/src/examples/coingecko/test/integration/fixtures.ts +0 -42
  118. package/src/examples/coingecko-old/batch-warming.ts +0 -79
  119. package/src/examples/coingecko-old/index.ts +0 -9
  120. package/src/examples/coingecko-old/rest.ts +0 -77
  121. package/src/examples/ncfx/config/index.ts +0 -12
  122. package/src/examples/ncfx/index.ts +0 -9
  123. package/src/examples/ncfx/websocket.ts +0 -99
  124. package/src/index.ts +0 -149
  125. package/src/metrics/constants.ts +0 -23
  126. package/src/metrics/index.ts +0 -115
  127. package/src/metrics/util.ts +0 -18
  128. package/src/rate-limiting/background/fixed-frequency.ts +0 -45
  129. package/src/rate-limiting/index.ts +0 -100
  130. package/src/rate-limiting/metrics.ts +0 -18
  131. package/src/rate-limiting/request/simple-counting.ts +0 -76
  132. package/src/transports/batch-warming.ts +0 -127
  133. package/src/transports/index.ts +0 -152
  134. package/src/transports/metrics.ts +0 -95
  135. package/src/transports/rest.ts +0 -168
  136. package/src/transports/util.ts +0 -63
  137. package/src/transports/websocket.ts +0 -245
  138. package/src/util/index.ts +0 -23
  139. package/src/util/logger.ts +0 -69
  140. package/src/util/recordRequests.ts +0 -47
  141. package/src/util/request.ts +0 -117
  142. package/src/util/subscription-set/expiring-sorted-set.ts +0 -54
  143. package/src/util/subscription-set/subscription-set.ts +0 -35
  144. package/src/util/test-payload-loader.ts +0 -87
  145. package/src/validation/error.ts +0 -116
  146. package/src/validation/index.ts +0 -110
  147. package/src/validation/input-params.ts +0 -45
  148. package/src/validation/override-functions.ts +0 -44
  149. package/src/validation/overrideFunctions.ts +0 -44
  150. package/src/validation/preset-tokens.json +0 -23
  151. package/src/validation/validator.ts +0 -384
  152. package/test/adapter.test.ts +0 -27
  153. package/test/background-executor.test.ts +0 -108
  154. package/test/cache/cache-key.test.ts +0 -114
  155. package/test/cache/helper.ts +0 -100
  156. package/test/cache/local.test.ts +0 -54
  157. package/test/cache/redis.test.ts +0 -89
  158. package/test/correlation.test.ts +0 -114
  159. package/test/index.test.ts +0 -37
  160. package/test/metrics/feed-id.test.ts +0 -38
  161. package/test/metrics/helper.ts +0 -14
  162. package/test/metrics/labels.test.ts +0 -36
  163. package/test/metrics/metrics.test.ts +0 -267
  164. package/test/metrics/redis-metrics.test.ts +0 -113
  165. package/test/metrics/warmer-metrics.test.ts +0 -193
  166. package/test/metrics/ws-metrics.test.ts +0 -225
  167. package/test/rate-limit-config.test.ts +0 -242
  168. package/test/smoke/smoke.test.ts +0 -166
  169. package/test/smoke/test-payload-fail.json +0 -3
  170. package/test/smoke/test-payload.js +0 -22
  171. package/test/smoke/test-payload.json +0 -7
  172. package/test/transports/batch.test.ts +0 -466
  173. package/test/transports/rest.test.ts +0 -242
  174. package/test/transports/websocket.test.ts +0 -183
  175. package/test/tsconfig.json +0 -5
  176. package/test/util.ts +0 -77
  177. package/test/validation.test.ts +0 -178
  178. package/test.sh +0 -20
  179. package/test2.sh +0 -2
  180. package/tsconfig.json +0 -28
  181. package/typedoc.json +0 -6
  182. package/webpack.config.js +0 -57
  183. 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
- })