@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,225 +0,0 @@
1
- import FakeTimers from '@sinonjs/fake-timers'
2
- import untypedTest, { TestFn } from 'ava'
3
- import axios, { AxiosError } from 'axios'
4
- import { Server, WebSocket } from 'mock-socket'
5
- import { AddressInfo } from 'net'
6
- import { expose } from '../../src'
7
- import { Adapter, AdapterEndpoint } from '../../src/adapter'
8
- import { DEFAULT_SHARED_MS_BETWEEN_REQUESTS } from '../../src/rate-limiting'
9
- import { DEFAULT_WS_TTL, WebSocketClassProvider, WebSocketTransport } from '../../src/transports'
10
- import { ProviderResult } from '../../src/util'
11
- import { InputParameters } from '../../src/validation'
12
- import { MockCache } from '../util'
13
- import { parsePromMetrics } from './helper'
14
-
15
- export const test = untypedTest as TestFn<{
16
- serverAddress: string
17
- cache: MockCache
18
- adapterEndpoint: AdapterEndpoint
19
- server: Server
20
- }>
21
-
22
- interface AdapterRequestParams {
23
- base: string
24
- quote: string
25
- }
26
-
27
- export const inputParameters: InputParameters = {
28
- base: {
29
- type: 'string',
30
- required: true,
31
- },
32
- quote: {
33
- type: 'string',
34
- required: true,
35
- },
36
- }
37
-
38
- interface ProviderMessage {
39
- pair: string
40
- value: number
41
- }
42
-
43
- const URL = 'wss://test-ws.com/asd'
44
-
45
- /**
46
- * Sets the mocked websocket instance in the provided provider class.
47
- * We need this here, because the tests will connect using their instance of WebSocketClassProvider;
48
- * fetching from this library to the \@chainlink/ea-bootstrap package would access _another_ instance
49
- * of the same constructor. Although it should be a singleton, dependencies are different so that
50
- * means that the static classes themselves are also different.
51
- *
52
- * @param provider - singleton WebSocketClassProvider
53
- */
54
- export const mockWebSocketProvider = (provider: typeof WebSocketClassProvider): void => {
55
- // Extend mock WebSocket class to bypass protocol headers error
56
- class MockWebSocket extends WebSocket {
57
- constructor(url: string, protocol: string | string[] | Record<string, string> | undefined) {
58
- super(url, protocol instanceof Object ? undefined : protocol)
59
- }
60
- }
61
-
62
- // Need to disable typing, the mock-socket impl does not implement the ws interface fully
63
- provider.set(MockWebSocket as any) // eslint-disable-line @typescript-eslint/no-explicit-any
64
- }
65
-
66
- export const websocketTransport = new WebSocketTransport({
67
- url: URL,
68
- handlers: {
69
- async open() {
70
- return
71
- },
72
-
73
- message(message: ProviderMessage): ProviderResult<AdapterRequestParams>[] {
74
- const [base, quote] = message.pair.split('/')
75
- return [
76
- {
77
- params: { base, quote },
78
- value: message.value,
79
- },
80
- ]
81
- },
82
- },
83
- builders: {
84
- subscribeMessage: (params: AdapterRequestParams) => ({
85
- request: 'subscribe',
86
- pair: `${params.base}/${params.quote}`,
87
- }),
88
- unsubscribeMessage: (params: AdapterRequestParams) => ({
89
- request: 'unsubscribe',
90
- pair: `${params.base}/${params.quote}`,
91
- }),
92
- },
93
- })
94
-
95
- const base = 'ETH'
96
- const quote = 'USD'
97
- const price = 1234
98
-
99
- export const webSocketEndpoint: AdapterEndpoint = {
100
- name: 'test',
101
- transport: websocketTransport,
102
- inputParameters,
103
- }
104
-
105
- const CACHE_MAX_AGE = 1000
106
-
107
- const adapter: Adapter = {
108
- name: 'test',
109
- defaultEndpoint: 'test',
110
- endpoints: [webSocketEndpoint],
111
- envDefaultOverrides: {
112
- CACHE_MAX_AGE,
113
- },
114
- }
115
-
116
- const clock = FakeTimers.install()
117
-
118
- test.before(async (t) => {
119
- process.env['METRICS_ENABLED'] = 'true'
120
- process.env['METRICS_PORT'] = '9093'
121
- // Disable retries to make the testing flow easier
122
- process.env['CACHE_POLLING_MAX_RETRIES'] = '0'
123
-
124
- // Mock WS
125
- mockWebSocketProvider(WebSocketClassProvider)
126
- const mockWsServer = new Server(URL, { mock: false })
127
- mockWsServer.on('connection', (socket) => {
128
- let counter = 0
129
- const parseMessage = () => {
130
- if (counter++ === 0) {
131
- socket.send(
132
- JSON.stringify({
133
- pair: `${base}/${quote}`,
134
- value: price,
135
- }),
136
- )
137
- }
138
- }
139
- socket.on('message', parseMessage)
140
- })
141
-
142
- // Create mocked cache so we can listen when values are set
143
- // This is a more reliable method than expecting precise clock timings
144
- const mockCache = new MockCache()
145
-
146
- // Start up adapter
147
- const server = await expose(adapter, {
148
- cache: mockCache,
149
- })
150
- t.context.serverAddress = `http://localhost:${(server?.address() as AddressInfo)?.port}`
151
- t.context.cache = mockCache
152
- t.context.server = mockWsServer
153
- })
154
-
155
- test.after(async () => {
156
- clock.uninstall()
157
- })
158
-
159
- test.serial('Test WS connection, subscription, and message metrics', async (t) => {
160
- const makeRequest = () =>
161
- axios.post(t.context.serverAddress, {
162
- data: {
163
- base,
164
- quote,
165
- },
166
- })
167
-
168
- // Expect the first response to time out
169
- // The polling behavior is tested in the cache tests, so this is easier here.
170
- // Start the request:
171
- const errorPromise: Promise<AxiosError | undefined> = t.throwsAsync(makeRequest)
172
- // Advance enough time for the initial request async flow
173
- clock.tickAsync(10)
174
- // Wait for the failed cache get -> instant 504
175
- const error = await errorPromise
176
- t.is(error?.response?.status, 504)
177
-
178
- // Advance clock so that the batch warmer executes once again and wait for the cache to be set
179
- const cacheValueSetPromise = t.context.cache.waitForNextSet()
180
- await clock.tickAsync(DEFAULT_SHARED_MS_BETWEEN_REQUESTS + 10)
181
- await cacheValueSetPromise
182
-
183
- // Second request should find the response in the cache
184
- let response = await makeRequest()
185
-
186
- t.is(response.status, 200)
187
-
188
- // Check connection, subscription active, subscription total, and message total metrics when subscribed to feed
189
- const metricsAddress = `http://localhost:${process.env['METRICS_PORT']}/metrics`
190
- response = await axios.get(metricsAddress)
191
- let metricsMap = parsePromMetrics(response.data)
192
- let expectedLabel = '{app_name="test",app_version="undefined"}'
193
- t.is(metricsMap.get(`ws_connection_active${expectedLabel}`), 1)
194
- expectedLabel =
195
- '{feed_id="|base:eth|quote:usd",subscription_key="test-|base:eth|quote:usd",app_name="test",app_version="undefined"}'
196
- t.is(metricsMap.get(`ws_subscription_active${expectedLabel}`), 1)
197
- t.is(metricsMap.get(`ws_subscription_total${expectedLabel}`), 1)
198
- t.is(metricsMap.get(`ws_message_total${expectedLabel}`), 1)
199
-
200
- // Wait until the cache expires, and the subscription is out
201
- await clock.tickAsync(Math.ceil(CACHE_MAX_AGE / DEFAULT_WS_TTL) * DEFAULT_WS_TTL + 1)
202
-
203
- // Now that the cache is out and the subscription no longer there, this should time out
204
- const error2: AxiosError | undefined = await t.throwsAsync(makeRequest)
205
- t.is(error2?.response?.status, 504)
206
-
207
- // Check connection, subscription active, subscription total, and message total metrics when unsubscribed from feed
208
- response = await axios.get(metricsAddress)
209
- metricsMap = parsePromMetrics(response.data)
210
- expectedLabel = '{app_name="test",app_version="undefined"}'
211
- t.is(metricsMap.get(`ws_connection_active${expectedLabel}`), 1)
212
- expectedLabel =
213
- '{feed_id="|base:eth|quote:usd",subscription_key="test-|base:eth|quote:usd",app_name="test",app_version="undefined"}'
214
- t.is(metricsMap.get(`ws_subscription_active${expectedLabel}`), 0)
215
- t.is(metricsMap.get(`ws_subscription_total${expectedLabel}`), 1)
216
- t.is(metricsMap.get(`ws_message_total${expectedLabel}`), 2)
217
-
218
- t.context.server.close()
219
-
220
- // Check connection metric after connection closed
221
- response = await axios.get(metricsAddress)
222
- metricsMap = parsePromMetrics(response.data)
223
- expectedLabel = '{app_name="test",app_version="undefined"}'
224
- t.is(metricsMap.get(`ws_connection_active${expectedLabel}`), 0)
225
- })
@@ -1,242 +0,0 @@
1
- import test from 'ava'
2
- import { expose } from '../src'
3
- import { Adapter, AdapterDependencies } from '../src/adapter'
4
- import { SimpleCountingRateLimiter } from '../src/rate-limiting'
5
- import { NopTransport } from './util'
6
-
7
- test('empty tiers in rate limiting fails on startup', async (t) => {
8
- const adapter: Adapter = {
9
- name: 'test',
10
- endpoints: [
11
- {
12
- name: 'test',
13
- inputParameters: {},
14
- transport: new NopTransport(),
15
- },
16
- ],
17
- rateLimiting: {
18
- tiers: {},
19
- },
20
- }
21
-
22
- await t.throwsAsync(async () => expose(adapter), {
23
- message: 'The tiers object is defined, but has no entries',
24
- })
25
- })
26
-
27
- test('selected tier is not a valid option', async (t) => {
28
- const adapter: Adapter = {
29
- name: 'test',
30
- endpoints: [
31
- {
32
- name: 'test',
33
- inputParameters: {},
34
- transport: new NopTransport(),
35
- },
36
- ],
37
- rateLimiting: {
38
- tiers: {
39
- free: {
40
- rateLimit1s: 123,
41
- },
42
- pro: {
43
- rateLimit1s: 1234,
44
- },
45
- },
46
- },
47
- envDefaultOverrides: {
48
- RATE_LIMIT_API_TIER: 'asdasdasd',
49
- },
50
- }
51
-
52
- await t.throwsAsync(async () => expose(adapter), {
53
- message: 'The selected rate limit tier "asdasdasd" is not valid (can be one of "free", "pro")',
54
- })
55
- })
56
-
57
- test('throws error if explicit allocation leaves no room for implicitly allocated endpoints', async (t) => {
58
- const adapter: Adapter = {
59
- name: 'test',
60
- endpoints: [
61
- {
62
- name: 'test',
63
- inputParameters: {},
64
- transport: new NopTransport(),
65
- rateLimiting: {
66
- allocationPercentage: 100,
67
- },
68
- },
69
- {
70
- name: 'test2',
71
- inputParameters: {},
72
- transport: new NopTransport(),
73
- },
74
- ],
75
- rateLimiting: {
76
- tiers: {
77
- free: {
78
- rateLimit1s: 123,
79
- },
80
- pro: {
81
- rateLimit1s: 1234,
82
- },
83
- },
84
- },
85
- envDefaultOverrides: {
86
- RATE_LIMIT_API_TIER: 'asdasdasd',
87
- },
88
- }
89
-
90
- await t.throwsAsync(async () => expose(adapter), {
91
- message: 'The explicit allocation is at 100% but there are endpoints with implicit allocation',
92
- })
93
- })
94
-
95
- test('throws error if explicit allocation exceeds 100%', async (t) => {
96
- const adapter: Adapter = {
97
- name: 'test',
98
- endpoints: [
99
- {
100
- name: 'test',
101
- inputParameters: {},
102
- transport: new NopTransport(),
103
- rateLimiting: {
104
- allocationPercentage: 80,
105
- },
106
- },
107
- {
108
- name: 'test2',
109
- inputParameters: {},
110
- transport: new NopTransport(),
111
- rateLimiting: {
112
- allocationPercentage: 30,
113
- },
114
- },
115
- ],
116
- rateLimiting: {
117
- tiers: {
118
- free: {
119
- rateLimit1s: 123,
120
- },
121
- pro: {
122
- rateLimit1s: 1234,
123
- },
124
- },
125
- },
126
- envDefaultOverrides: {
127
- RATE_LIMIT_API_TIER: 'asdasdasd',
128
- },
129
- }
130
-
131
- await t.throwsAsync(async () => expose(adapter), {
132
- message: 'The total allocation set for all endpoints summed cannot exceed 100%',
133
- })
134
- })
135
-
136
- test('uses most restrictive tier if none is specified in settings', async (t) => {
137
- const adapter: Adapter = {
138
- name: 'test',
139
- endpoints: [
140
- {
141
- name: 'test',
142
- inputParameters: {},
143
- transport: new (class extends NopTransport {
144
- override async initialize(dependencies: AdapterDependencies): Promise<void> {
145
- t.true(dependencies.requestRateLimiter instanceof SimpleCountingRateLimiter)
146
- t.is(
147
- (dependencies.requestRateLimiter as unknown as Record<string, number>)[
148
- 'perSecondLimit'
149
- ],
150
- 123,
151
- )
152
- }
153
- })(),
154
- },
155
- ],
156
- rateLimiting: {
157
- tiers: {
158
- asd: {
159
- rateLimit1s: 5234,
160
- rateLimit1m: 3000 * 60,
161
- },
162
- free: {
163
- rateLimit1s: 123,
164
- rateLimit1h: 1000 * 60,
165
- },
166
- pro: {
167
- rateLimit1m: 1234 * 60,
168
- },
169
- },
170
- },
171
- }
172
-
173
- await expose(adapter)
174
- })
175
-
176
- test('uses unlimited tier if none is specified in settings', async (t) => {
177
- const adapter: Adapter = {
178
- name: 'test',
179
- endpoints: [
180
- {
181
- name: 'test',
182
- inputParameters: {},
183
- transport: new (class extends NopTransport {
184
- override async initialize(dependencies: AdapterDependencies): Promise<void> {
185
- t.true(dependencies.requestRateLimiter instanceof SimpleCountingRateLimiter)
186
- t.is(
187
- (dependencies.requestRateLimiter as unknown as Record<string, number>)[
188
- 'perSecondLimit'
189
- ],
190
- Infinity,
191
- )
192
- }
193
- })(),
194
- },
195
- ],
196
- }
197
-
198
- await expose(adapter)
199
- })
200
-
201
- test('uses specified tier if present in settings', async (t) => {
202
- const adapter: Adapter = {
203
- name: 'test',
204
- endpoints: [
205
- {
206
- name: 'test',
207
- inputParameters: {},
208
- transport: new (class extends NopTransport {
209
- override async initialize(dependencies: AdapterDependencies): Promise<void> {
210
- t.true(dependencies.requestRateLimiter instanceof SimpleCountingRateLimiter)
211
- t.is(
212
- (dependencies.requestRateLimiter as unknown as Record<string, number>)[
213
- 'perSecondLimit'
214
- ],
215
- 1234,
216
- )
217
- }
218
- })(),
219
- },
220
- ],
221
- rateLimiting: {
222
- tiers: {
223
- asd: {
224
- rateLimit1s: 5234,
225
- rateLimit1m: 3000 * 60,
226
- },
227
- free: {
228
- rateLimit1s: 123,
229
- rateLimit1h: 1000 * 60,
230
- },
231
- pro: {
232
- rateLimit1s: 1234,
233
- },
234
- },
235
- },
236
- envDefaultOverrides: {
237
- RATE_LIMIT_API_TIER: 'pro',
238
- },
239
- }
240
-
241
- await expose(adapter)
242
- })
@@ -1,166 +0,0 @@
1
- import untypedTest, { TestFn } from 'ava'
2
- import axios, { AxiosError, 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 { loadTestPayload } from '../../src/util/test-payload-loader'
11
-
12
- const test = untypedTest as TestFn
13
-
14
- const URL = 'http://test-url.com'
15
- const endpoint = '/price'
16
-
17
- interface AdapterRequestParams {
18
- from: string
19
- to: string
20
- }
21
-
22
- interface ProviderRequestBody {
23
- base: string
24
- quote: string
25
- }
26
-
27
- interface ProviderResponseBody {
28
- price: number
29
- }
30
-
31
- const createAdapterEndpoint = (): AdapterEndpoint => {
32
- const restEndpointTransport = new RestTransport<
33
- AdapterRequestParams,
34
- ProviderRequestBody,
35
- ProviderResponseBody,
36
- EmptySettings
37
- >({
38
- prepareRequest: (
39
- req: AdapterRequest<AdapterRequestParams>,
40
- ): AxiosRequestConfig<ProviderRequestBody> => {
41
- return {
42
- baseURL: URL,
43
- url: endpoint,
44
- method: 'GET',
45
- params: {
46
- base: req.requestContext.data.from,
47
- quote: req.requestContext.data.to,
48
- },
49
- }
50
- },
51
- parseResponse: (
52
- req: AdapterRequest<AdapterRequestParams>,
53
- res: AxiosResponse<ProviderResponseBody>,
54
- ): AdapterResponse<ProviderResponseBody> => {
55
- return {
56
- data: res.data,
57
- statusCode: 200,
58
- result: res.data.price,
59
- }
60
- },
61
- options: {
62
- coalescing: true,
63
- },
64
- })
65
-
66
- return {
67
- name: 'test',
68
- inputParameters: {
69
- from: {
70
- type: 'string',
71
- required: true,
72
- },
73
- to: {
74
- type: 'string',
75
- required: true,
76
- },
77
- },
78
- transport: restEndpointTransport,
79
- }
80
- }
81
-
82
- const adapter: Adapter = {
83
- name: 'test',
84
- defaultEndpoint: 'test',
85
- endpoints: [createAdapterEndpoint()],
86
- }
87
-
88
- test.before(async () => {
89
- nock.disableNetConnect()
90
- nock.enableNetConnect('localhost')
91
- })
92
-
93
- test.after(() => {
94
- nock.restore()
95
- })
96
-
97
- const base = 'ETH'
98
- const quote = 'USD'
99
- const price = 1234
100
-
101
- test('Test payload loader static', async (t) => {
102
- const testPayload = loadTestPayload('test/smoke/test-payload.json')
103
- if (testPayload.isDefault) {
104
- t.fail('Test payload loader return isDefault request unexpectedly')
105
- return
106
- }
107
- t.deepEqual(testPayload.requests[0], { from: base, to: quote })
108
- })
109
-
110
- test('Test payload loader dynamic', async (t) => {
111
- const testPayload = loadTestPayload('test/smoke/test-payload.js')
112
- if (testPayload.isDefault) {
113
- t.fail('Test payload loader return isDefault request unexpectedly')
114
- return
115
- }
116
- t.deepEqual(testPayload.requests[0], { from: 'ETH', to: 'USD' })
117
- t.deepEqual(testPayload.requests[1], { from: 'ETH', to: 'JPY' })
118
- t.deepEqual(testPayload.requests[2], { from: 'BTC', to: 'USD' })
119
- t.deepEqual(testPayload.requests[3], { from: 'BTC', to: 'JPY' })
120
- })
121
-
122
- test.only('Test payload loader bad file name', async (t) => {
123
- const testPayload = loadTestPayload('test/smoke/test-payload-bad.json')
124
- t.is(testPayload.isDefault, true)
125
- })
126
-
127
- test.serial('Test smoke endpoint success', async (t) => {
128
- process.env['SMOKE_TEST_PAYLOAD_FILE_NAME'] = 'test/smoke/test-payload.json'
129
- const server = await expose(adapter)
130
- if (!server) {
131
- throw 'Server did not start'
132
- }
133
- const address = `http://localhost:${(server?.address() as AddressInfo)?.port}`
134
- const instance = nock(URL)
135
- .get(endpoint)
136
- .query({
137
- base,
138
- quote,
139
- })
140
- .reply(200, { price })
141
- let response: AxiosResponse
142
- try {
143
- response = await axios.get(`${address}/smoke`)
144
- } catch (e: unknown) {
145
- t.fail('Smoke endpoint errored unexpectedly')
146
- return
147
- }
148
- t.is(response.data, 'OK')
149
- instance.done()
150
- })
151
-
152
- test.serial('Test smoke endpoint failure', async (t) => {
153
- process.env['SMOKE_TEST_PAYLOAD_FILE_NAME'] = 'test/smoke/test-payload-fail.json'
154
- const server = await expose(adapter)
155
- if (!server) {
156
- throw 'Server did not start'
157
- }
158
- const address = `http://localhost:${(server?.address() as AddressInfo)?.port}`
159
- try {
160
- await axios.get(`${address}/smoke`)
161
- } catch (e: unknown) {
162
- t.is((e as AxiosError).response?.status, 500)
163
- return
164
- }
165
- t.fail('Smoke endpoint passed unexpectedly')
166
- })
@@ -1,3 +0,0 @@
1
- {
2
- "requests": [{ "from": "" }]
3
- }
@@ -1,22 +0,0 @@
1
- const fromVariables = ['ETH', 'BTC']
2
-
3
- const toVariables = ['USD', 'JPY']
4
-
5
- function generateTestPayload() {
6
- const payload = {
7
- requests: [],
8
- }
9
-
10
- for (const from of fromVariables) {
11
- for (const to of toVariables) {
12
- payload.requests.push({
13
- from,
14
- to,
15
- })
16
- }
17
- }
18
-
19
- return JSON.stringify(payload)
20
- }
21
-
22
- module.exports = generateTestPayload()
@@ -1,7 +0,0 @@
1
- {
2
- "requests": [{
3
- "from": "ETH",
4
- "to": "USD"
5
- }]
6
- }
7
-